2014-10-30 13 views
5

ich dabei bin Elixier des Lernens und kam über etwas, das keinen Sinn für mich gemacht hat ...String.replace Rückkehr binäre Darstellung von String

Ich versuche, Zeichensetzung

"Freude schöner Götterfunken" |> String.replace(~r/[^\s\w]/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>> 
"Freude schöner Götterfunken" |> String.replace(~r/[^\w]/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>> 
"Freude schöner Götterfunken" |> String.replace(~r/\p{P}/, "") #=> <<70, 114, 101, 117, 100, 101, 32, 115, 99, 104, 195, 110, 101, 114, 32, 71, 195, 116, 116, 101, 114, 102, 117, 110, 107, 101, 110>> 
"Freude schöner Götterfunken" |> String.replace(~r/\s/, "") #=> FreudeschönerGötterfunken 
"Hi my name is bob" |> String.replace(~r/\w/, "") #=> " " 
Regex.run(~r/[^\w]/, "Freude schöner Götterfunken") #=> [<<182>>] 
zu entfernen

Dies scheint wie ein Fehler, aber als ein Noob nehme ich Ignoranz. Warum ersetzt das Ersetzen die Zeichenfolge nicht?

Antwort

17

Sie haben recht, dass String.replace/2 keine Zeichenfolge zurückgibt, da Elixir Zeichenfolgen als utf-8-codierte Binärdateien definiert. Dies ist jedoch kein Fehler, da Elixir erwartet, dass Sie gültige Operationen an den Argumenten übergeben oder ausführen, da nicht alle Ergebnisse überprüft werden (da sie teuer sind).

Wenn Sie zum Beispiel eines der obigen Binärdateien an String.downcase/1 übergeben, wird Elixir die Teile, die es kennt, herunterrechnen und den Rest ignorieren. Der Grund dafür ist, dass UTF-8 automatisch synchronisiert wird. Wenn wir etwas komisches sehen, können wir das seltsame Byte überspringen und die Operation fortsetzen. Mit anderen Worten, die Philosophie des String-Handlings in Elixir besteht darin, an den Grenzen zu validieren (wie beim Öffnen von Dateien, Ein-/Ausgaben oder Lesen aus einer Datenbank) und davon auszugehen, dass wir mit gültigen Operationen arbeiten und diese ausführen.

OK, mit allem, was gesagt, warum Ihr Code nicht funktioniert? Der Grund dafür ist, dass in Ihrer Regex kein Unicode aktiviert ist. Lassen Sie uns die u Modifikator fügen Sie dann:

iex> "Freude schöner Götterfunken" |> String.replace(~r/[^\s\w]/u, "") 
"Freude schöner Götterfunken" 

Nun, ist es nicht Ihr Problem lösen, aber zumindest das Ergebnis gültig ist. Reading about unicode categories here bedeutet, dass wir dieses Problem mit Unicode-Eigenschaften nicht wirklich lösen können, da ö in Ihrem Beispiel ein einzelner Codepunkt ist, der der \p{L}-Eigenschaft entspricht.

Vielleicht die einfachste Lösung in diesem Fall, vorausgesetzt, Sie wollen es nur für deutsche zu lösen, ist nur die binäre durchqueren die Bytes halten < = 127. Etwas wie:

iex> for <<x <- "Freude schöner Götterfunken">>, x <= 127, into: "", do: <<x>> 
"Freude schner Gtterfunken" 

Wenn Sie mehr wollen vollständige Lösung, sollten Sie wahrscheinlich in Unicode Transliteration suchen.

+0

Super Antwort! Danke für die ausführliche Erklärung. Ich verpasse den Modifikator u beim Lesen der Dokumente. – matmer

0

String.replace gibt eine "Zeichenkette" zurück, aber doppelt zitierte Zeichenketten werden tatsächlich als Binärdateien in Elixir gespeichert. Aus irgendeinem Grund kann die Ausgabe nicht als reguläre Zeichenfolge angezeigt werden, daher wird auf die Darstellung der Binärdarstellung zurückgegriffen.

+1

Die "aus irgendeinem Grund" ist hier: http://elixir-lang.org/getting_started/6.html#6.3-char-lists. Beachten Sie den folgenden Satz: "(Beachten Sie, dass iex nur Codepunkte ausgibt, wenn einer der Zeichen außerhalb des ASCII-Bereichs liegt)." Da @matmer Zeichen hatte, die außerhalb des ASCII-Bereichs lagen, wurde das Ganze als Codepunkte angezeigt. –

Verwandte Themen