Wie greppt man Zeichen anhand ihres Unicode-Werts?

Wie greppt man Zeichen anhand ihres Unicode-Werts?

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.txterhalte 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:

  1. 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.

  2. 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.

  3. 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, pcre2grepoder pcregrepjeder grepImplementierung, 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 \xe9fü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_UTFan die Regexp-Engine entspricht), obwohl neuere Versionen von GNU grepdies zumindest automatisch tun, wenn es in einem Gebietsschema aufgerufen wird, das UTF-8 als Zeichenzuordnung verwendet. Mit pcregrepund pcre2grepkann dies auch mit der Option aktiviert werden -u(siehe auch -Uin pcre2grep).

In perlerfolgt dies über die -COption (big char) der PERL_UNICODEUmgebungsvariable. Wobei -Callein die Abkürzung für -CSDLzum Dekodieren/Umkodieren von Eingabe/Ausgabe als UTF-8 dient, wenn das Gebietsschema UTF-8 verwendet, wie es GNU greptut, oder mit -CSDzum bedingungslosen Dekodieren oder zum expliziten Dekodieren aus jeder beliebigen Kodierung, beispielsweise unter Verwendung des EncodeModuls.

In perlund PCRE2 (wie von pcre2grepoder in neueren Versionen von GNU verwendet grep) können Sie auch verwenden \N{U+16A0}. Und in perlseinem 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 \xHHfunktionieren sie auf Grundlage des Wertes (dem Codepunkt im entsprechenden Zeichensatz, nicht in Unicode).

Beispielsweise im en_GB.iso885915Gebietsschema, 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 perluse -Mopen=localeanstelle von , -Cum 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.iso885915zum Zeitpunkt der $'\u20ac'Analyse durch die Shell noch nicht ausgeführt worden war.

verwandte Informationen