Ich habe das Unicode-Zeichen ᚠ, dargestellt durch seinen Unicode-Codepunkt 16A0, in einer Textdatei (die Textdatei ist als UTF-8 codiert(?).
Wenn ich das mache, grep '\u16A0' test.txt
erhalte ich kein Ergebnis. Wie greppe ich dieses Zeichen?
Antwort1
Sie könnenANSI-C-Zitatvon Ihrer Shell bereitgestellt, um durch Backslash maskierte Zeichen gemäß dem ANSI-C-Standard zu ersetzen. Dies sollte für jeden Befehl funktionieren, nicht nur für grep
, in Shells wie Bash und Zsh:
grep $'\u16A0'
Für einige komplexere Beispiele verweisen wir aufdiese verwandte Frageund seine Antworten.
Antwort2
Du könntest benutzenugrepals Drop-In-Ersatz für grep, um dem Unicode-Codepunkt U+16A0 zu entsprechen:
ugrep '\x{16A0}' test.txt
Es verwendet dieselben Optionen wie grep, bietet jedoch weitaus mehr Funktionen, beispielsweise:
ugrep durchsucht UTF-8/16/32-Eingabe und andere FormateMit der Option -Q können viele weitere Dateiformate durchsucht werden, beispielsweise ISO-8859-1 bis 16, EBCDIC, Codepages 437, 850, 858, 1250 bis 1258, MacRoman und KIO8.
ugrep stimmt mit Unicode-Mustern übereinstandardmäßig (deaktiviert mit Option -U). Die Syntax des regulären Ausdrucksmusters ist POSIX ERE-kompatibel und wurde mit einer PCRE-ähnlichen Syntax erweitert. Option -P kann auch für Perl-Abgleiche mit Unicode-Mustern verwendet werden.
Sehenugrep auf GitHubfür Details.
Antwort3
Verwenden vonRaku(früher bekannt als Perl_6)
Beispieleingabe:
https://www.cogsci.ed.ac.uk/~richard/unicode-sample-3-2.html
Ordnen Sie das Zeichen zu und drucken Sie die Zeile:
~$ raku -ne '.put if m/ \x[16A0] /;' file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ
#OR:
~$ raku -e 'lines.grep(/ \x[16A0] /).put;' file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ
Ordnen Sie das Zeichen zu und drucken Sie das (durch Leerzeichen getrennte) „Wort“:
~$ raku -ne 'for .words() { .put if m/ \x[16A0] / };' file
ᚠ
#OR:
~$ raku -e 'words.grep(/ \x[16A0] /).put;' file
ᚠ
Ordnen Sie das Zeichen zu und drucken Sie die (genauen) Übereinstimmungen:
~$ raku -e 'given slurp() { put m:g/ \x[16A0] / };' file
ᚠ
#OR:
~$ raku -e 'slurp.match(:global,/ \x[16A0] /).put;' file
ᚠ
Ordnen Sie das Zeichen zu, zählen Sie die Übereinstimmungen und drucken Sie:
~$ raku -e 'given slurp() { put m:g/ \x[16A0] /.Int };' file
1
#OR:
~$ raku -e 'slurp.match(:global,/ \x[16A0] /).elems.put;' file
1
ANMERKUNGEN:
In Raku können Sie genauso einfach einen Abgleich mit einem Unicode-Namen wie durchführen
\c[RUNIC LETTER FEHU FEOH FE F]
, was dieselben Ergebnisse liefert wie der Abgleich mit\x[16A0]
oben.In Raku können Sie genauso einfach einen Abgleich mit einem Unicode-Zeichen wie durchführen
ᚠ
, was die gleichen Ergebnisse liefert wie ein Abgleich mit\x[16A0]
oder\c[RUNIC LETTER FEHU FEOH FE F]
oben.In Raku können Sie Unicode-Variablen (sowie Unicode-Operatoren) verwenden. So funktioniert es:
~$ raku -e 'my $ᚠ = slurp.match(/ \x[16A0] /); say $ᚠ.Str.raku;' file
"ᚠ"
https://docs.raku.org/language/regexes#Unicode_properties
https://docs.raku.org/language/unicode
https://docs.raku.org
https://raku.org
Antwort4
Mit perl
, pcre2grep
oder pcregrep
jeder grep
Implementierung, die zumindest PCRE oder PCRE2 verwendet oder verwenden kann, können Sie \x{16A0}
zum Abgleichen mit dem Zeichen mit dem Wert verwenden 0x16A0
(oder nur \xe9
für Werte <= 0xff).
Damit dieser Wert der Unicode-Codepunkt ist, müssen wir ihnen mitteilen, dass die Eingabe aus UTF-8 dekodiert werden muss. In PCRE/PCRE2 geschieht dies durch die Verwendung von (*UTF)
am Anfang des Musters (was größtenteils der Übergabe PCRE_UTF
an die Regexp-Engine entspricht), obwohl neuere Versionen von GNU grep
dies zumindest automatisch tun, wenn es in einem Gebietsschema aufgerufen wird, das UTF-8 als Zeichenzuordnung verwendet. Mit pcregrep
und pcre2grep
kann dies auch mit der Option aktiviert werden -u
(siehe auch -U
in pcre2grep
).
In perl
erfolgt dies über die -C
Option (big char) der PERL_UNICODE
Umgebungsvariable. Wobei -C
allein die Abkürzung für -CSDL
zum Dekodieren/Umkodieren von Eingabe/Ausgabe als UTF-8 dient, wenn das Gebietsschema UTF-8 verwendet, wie es GNU grep
tut, oder mit -CSD
zum bedingungslosen Dekodieren oder zum expliziten Dekodieren aus jeder beliebigen Kodierung, beispielsweise unter Verwendung des Encode
Moduls.
In perl
und PCRE2 (wie von pcre2grep
oder in neueren Versionen von GNU verwendet grep
) können Sie auch verwenden \N{U+16A0}
. Und in perl
seinem Unicode-Namen: \N{RUNIC LETTER FEHU FEOH FE F}
.
Also:
perl -C -ne 'print if /\x{16A0}/'
perl -C -ne 'print if /\N{U+16A0}/'
perl -C -ne 'print if /\N{RUNIC LETTER FEHU FEOH FE F}/'
PERL_UNICODE=SD perl -ne 'print if /\x{16A0}/'
pcregrep -u '\x{16A0}'
pcregrep '(*UTF)\x{16A0}'
pcre2grep -u '\x{16A0}'
pcre2grep '(*UTF)\x{16A0}'
pcre2grep -U '\x{16A0}'
pcre2grep -u '\N{U+16A0}'
grep -P '\x{16A0}'
Um ein Zeichen basierend auf seinem Unicode-Wert in einer Eingabe abzugleichen, die nicht in UTF-8 codiert ist, funktionieren diese nicht, da sie nur in UTF-8 funktionieren. In Einzelbyte-Zeichensätzen \xHH
funktionieren sie auf Grundlage des Wertes (dem Codepunkt im entsprechenden Zeichensatz, nicht in Unicode).
Beispielsweise im en_GB.iso885915
Gebietsschema, wo sich das Eurozeichen (U+20AC) bei 0xA4 befindet.
$ LC_ALL=en_GB.iso885915 luit
$ locale charmap
ISO-8859-15
$ printf %s € | od -An -vtx1
a4
$ echo € | grep -P '\x{20ac}'
grep: character code point value in \x{} or \o{} is too large
$ echo € | grep -P '\N{U+20ac}'
grep: \N{U+dddd} is supported only in Unicode (UTF) mode
$ echo € | grep -P '(*UTF)\N{U+20ac}'
$ echo € | grep -P '\xA4'
€
Die Optionen wären also, den Text in UTF-8 zu konvertieren:
$ echo € | iconv -t utf-8 | LC_ALL=C.UTF-8 grep -P '\x{20ac}' | iconv -f utf-8
€
Oder verwenden Sie perl
use -Mopen=locale
anstelle von , -C
um die Eingabe/Ausgabe gemäß dem Zeichensatz des Gebietsschemas und nicht als UTF-8 zu dekodieren/kodieren:
$ echo € | perl -Mopen=locale -ne 'print if /\N{U+20ac}/'
€
Oder führen Sie keine Dekodierung durch, sondern gleichen Sie den Bytewert dieses Zeichens im Gebietsschema ab.
Beispielsweise mit GNU oder zsh oder neueren Versionen von bash printf
:
$ locale charmap
ISO-8859-15
$ printf '\u20ac' | od -An -vtx1
a4
$ echo € | grep -F -- "$(printf '\u20ac')"
€
In zsh können Sie auch $'\u20ac'
„which“ verwenden, um die Kodierung des Zeichens im aktuellen Gebietsschema zu diesem Zeitpunkt zu erweitern (und einen Fehler zu melden, wenn in diesem Gebietsschema kein solches Zeichen vorhanden ist).
$ echo € | grep -F -- $'\u20ac'
€
Mehrere andere Shells haben das $'\uHHHH'
seitdem von zsh kopiert, darunter ksh93, bash, mksh und einige ash-basierte Shells, allerdings mit einigen bedauerlichen Unterschieden: In ksh wird das unabhängig vom Gebietsschema in UTF-8 erweitert, und bei bash wird das in dem Gebietsschema erweitert, wenn der Code gelesen wird, und nicht zu dem Zeitpunkt, an dem der Code ausgeführt wird. So zum Beispiel in bash
:
LC_CTYPE=C.UTF-8
{
LC_CTYPE=en_GB.iso885915
printf '\xA4\n' | grep -F -- $'\u20ac'
}
Oder:
LC_CTYPE=C.UTF-8
euro() {
grep -F -- $'\u20ac'
}
LC_CTYPE=en_GB.iso885915
printf '\xa4\n' | euro
Funktioniert nicht, da in beiden Fällen $'\u20ac'
auf die UTF-8-Kodierung erweitert wird, da es LC_CTYPE=en_GB.iso885915
zum Zeitpunkt der $'\u20ac'
Analyse durch die Shell noch nicht ausgeführt worden war.