如何用 unicode 值來 grep 字元?

如何用 unicode 值來 grep 字元?

我在文字檔案中有 Unicode 字元 ᚠ,由其 Unicode 代碼點 16A0 表示(該文字檔案被編碼(?)為 utf-8)。

當我這樣做時,grep '\u16A0' test.txt我沒有得到任何結果。我如何 grep 該字元?

答案1

您可以使用ANSI-C 引用由 shell 提供,用於取代 ANSI C 標準指定的反斜線轉義字元。這應該適用於任何命令,而不僅僅是grepBash 和 Zsh 等 shell 中的命令:

grep $'\u16A0'

對於一些更複雜的例子,你可以參考這個相關問題及其答案。

答案2

你可以使用烏格勒普作為 grep 的直接替換,以匹配 Unicode 代碼點 U+16A0:

ugrep '\x{16A0}' test.txt

它採用與 grep 相同的選項,但提供更多的功能,例如:

ugrep 搜尋 UTF-8/16/32 輸入和其他格式。選項 -Q 允許搜尋許多其他檔案格式,例如 ISO-8859-1 到 16、EBCDIC、代碼頁 437、850、858、1250 到 1258、MacRoman 和 KIO8。

ugrep 匹配 Unicode 模式預設情況下(使用選項 -U 停用)。正規表示式模式語法符合 POSIX ERE 標準,並使用類似 PCRE 的語法進行了擴展。選項 -P 也可用於 Perl 與 Unicode 模式的匹配。

GitHub 上的 ugrep了解詳情。

答案3

使用(以前稱為 Perl_6)

輸入範例:

https://www.cogsci.ed.ac.uk/~richard/unicode-sample-3-2.html


匹配字符,列印行:

~$ raku -ne '.put if m/ \x[16A0] /;'  file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

#OR:

~$ raku -e  'lines.grep(/ \x[16A0] /).put;'  file
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

匹配字符,列印(空格分隔的)“word”:

~$ raku -ne 'for .words() { .put if m/ \x[16A0] / };'  file

#OR:

~$ raku -e  'words.grep(/ \x[16A0] /).put;'  file

匹配字符,列印(精確)匹配:

~$ raku -e 'given slurp() { put m:g/  \x[16A0]  / };'   file

#OR:

~$ raku -e 'slurp.match(:global,/  \x[16A0]  /).put;'   file

匹配字符,計算匹配次數並列印:

~$ raku -e 'given slurp() { put m:g/  \x[16A0]  /.Int };'   file
1

#OR:

~$ raku -e 'slurp.match(:global,/  \x[16A0]  /).elems.put;'   file
1 

筆記:

  1. 在 Raku 中,您可以輕鬆地匹配 Unicode 名稱\c[RUNIC LETTER FEHU FEOH FE F],例如 ,它給出的結果與上面的匹配結果相同\x[16A0]

  2. 在 Raku 中,您可以輕鬆地匹配 Unicode 字符,例如,其給出的結果與匹配或以上匹配的結果相同。\x[16A0]\c[RUNIC LETTER FEHU FEOH FE F]

  3. 在 Raku 中,您可以使用 Unicode 變數(以及 Unicode 運算子)。所以這有效:

~$ 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

答案4

使用perlpcre2grep或至少使用或可以使用 PCRE 或 PCRE2 的pcregrep任何實現,您可以用於匹配具有值的字元(或僅用於值 <= 0xff)。grep\x{16A0}0x16A0\xe9

為了使該值成為 unicode 代碼點,我們需要告訴他們輸入必須從 UTF-8 解碼。在 PCRE/PCRE2 中,這是透過(*UTF)在模式的開頭使用(主要相當於傳遞PCRE_UTF給正規表示式引擎),儘管最新版本的 GNUgrep至少在使用UTF-8 作為其字元映射的語言環境中呼叫時會自動執行此操作。對於pcregreppcre2grep,也可以使用 選項來啟用它-u(另請參見-Upcre2grep

在 中perl,這是透過環境變數-C的 (big char) 選項PERL_UNICODE。單獨使用時-C,縮寫是-CSDL如果語言環境像 GNU 一樣使用 UTF-8,則解碼/重新編碼將輸入/輸出重新編碼為 UTF-8 grep,或者-CSD無條件地執行此操作,或者使用模組等從任何編碼明確解碼Encode

在PCRE2(由GNU 或最新版本perl使用)中,您也可以使用.其 Unicode 名稱為: .pcre2grepgrep\N{U+16A0}perl\N{RUNIC LETTER FEHU FEOH FE F}

所以:

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}'

要根據未以 UTF-8 編碼的輸入上的 Unicode 值匹配字符,這些字符將不起作用,因為它們只能在 UTF-8 中起作用。在單字節字元集中,將按\xHH值(對應字元集中的代碼點,而不是 Unicode 中的代碼點)運作。

例如,在en_GB.iso885915區域設定中,歐元符號 (U+20AC) 位於 0xA4。

$ 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'

因此選項是將文字轉換為 UTF-8:

$ echo € | iconv -t utf-8 | LC_ALL=C.UTF-8 grep -P '\x{20ac}' | iconv -f utf-8

或者,如果使用perluse-Mopen=locale而不是-C告訴它根據語言環境的字元集而不是 UTF-8 對輸入/輸出進行解碼/編碼:

$ echo € | perl -Mopen=locale -ne 'print if /\N{U+20ac}/'

或不進行任何解碼,但匹配區域設定中該字元的位元組值。

例如,使用 GNU 或 zsh 或最新版本的 bash printf

$ locale charmap
ISO-8859-15
$ printf '\u20ac' | od -An -vtx1
 a4
$ echo € | grep -F -- "$(printf '\u20ac')"

在 zsh 中,您還可以使用$'\u20ac'which 將擴展為當時當前語言環境中字符的編碼(如果該語言環境中沒有此類字符,則報告錯誤)。

$ echo € | grep -F -- $'\u20ac'

其他幾個 shell 也從 zsh 複製了它$'\uHHHH',包括ksh93、bash、mksh 和一些基於ash 的shell,但有一些不幸的差異:在ksh 中,無論語言環境如何,它都會以UTF-8 進行擴展,而對於bash,它會在讀取程式碼時的語言環境而不是執行程式碼時的語言環境,例如,在bash

LC_CTYPE=C.UTF-8
{
  LC_CTYPE=en_GB.iso885915
  printf '\xA4\n' | grep -F -- $'\u20ac'
}

或者:

LC_CTYPE=C.UTF-8
euro() {
  grep -F -- $'\u20ac'
}
LC_CTYPE=en_GB.iso885915
printf '\xa4\n' | euro

不起作用,因為在這兩種情況下,$'\u20ac'都會擴展為其 UTF-8 編碼,因為在 shell 解析LC_CTYPE=en_GB.iso885915時尚未運行。$'\u20ac'

相關內容