Unicode 値を使用して文字を grep するにはどうすればよいでしょうか?

Unicode 値を使用して文字を grep するにはどうすればよいでしょうか?

テキスト ファイル内に、Unicode コード ポイント 16A0 で表される Unicode 文字 ᚠ があります (テキスト ファイルは utf-8 としてエンコードされています)。

そうすると、grep '\u16A0' test.txt結果が返されません。その文字を grep するにはどうすればいいでしょうか?

答え1

使用できますANSI-C 引用符シェルによって提供される を使用し、ANSI C 標準で指定されているバックスラッシュ エスケープ文字を置き換えます。これは、grepBash や Zsh などのシェルでは、 だけでなく、任意のコマンドで機能します。

grep $'\u16A0'

より複雑な例については、以下を参照してください。この関連する質問そしてその答え。

答え2

使用できるugrepUnicode コード ポイント U+16A0 に一致する grep の代替として:

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 で無効)。正規表現パターン構文は、PCRE のような構文で拡張された POSIX ERE 準拠です。オプション -P は、Unicode パターンとの Perl マッチングにも使用できます。

見る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
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ ᛰ

文字と一致し、(空白で区切られた)「単語」を出力します。

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

perl、、pcre2grepまたは少なくとも PCRE または PCRE2 を使用するか使用できる実装では、 を使用して、pcregrep値(または値 <= 0xff のみ) を持つ文字に一致させることができます。grep\x{16A0}0x16A0\xe9

その値が Unicode コード ポイントであるためには、入力が UTF-8 からデコードされる必要があることを指示する必要があります。PCRE/PCRE2 では、(*UTF)パターンの先頭で を使用します (PCRE_UTF正規表現エンジンに渡すこととほぼ同じ)。ただし、GNU の最近のバージョンgrepでは、少なくとも UTF-8 を charmap として使用するロケールで呼び出されたときには自動的に実行されます。 および ではpcregrep、オプションを使用しpcre2grepてこれを有効にすることもできます-u( の も参照-U) pcre2grep

では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

または、の代わりにperlを使用する場合は、UTF-8 ではなくロケールの文字セットに従って入力/出力をデコード/エンコードするように指示します。-Mopen=locale-C

$ 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 では、その時点の現在のロケールの文字のエンコーディングに展開する which を使用することもできます$'\u20ac'(そのロケールにそのような文字が存在しない場合はエラーを報告します)。

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

それ以来、ksh93、bash、mksh、およびいくつかのashベースのシェルを含むいくつかの他のシェルが$'\uHHHH'zshからこれをコピーしてきましたが、残念なことにいくつかの違いがあります。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 エンコーディングに展開されるため、動作しません。LC_CTYPE=en_GB.iso885915$'\u20ac'

関連情報