Unicode块的命令行过滤

时间:2018-01-29 23:55:32

标签: perl unicode grep

我已经尝试了几个小时来创建一个概念上简单的过滤器,我可以在命令行上使用,但没有成功。任务是过滤掉包含Hangul Jamo字符的所有行,同时保留所有其他行(可能包含ASCII,Hangul Syllable块中的字符等)。

例如,如果输入是

 foo
 ᅤᆨ
 간

输出将包含第一行和第三行,但不包含第二行,因为第二行包含Jamo字符。 (以上并不是真正的韩语,只是一个简单的测试用例。)

我对Gnu grep实用程序(版本2.20)非常失望。我会想到ff。会工作:

grep -Pv '[\x{1100}-\x{11FF}]'

但我收到错误消息grep: character value in \x{...} sequence is too large。 (\ u1100语法,实际的Perl语法,根本不受支持。)

(我注意到我们的版本2.20已经相当老了。如果有人尝试使用更新版本的grep进行上述操作,并且它有效,我肯定会认为这是一个答案 - 我会让我们的IT人员来升级!)

我尝试了sed,但没有进一步。 (对不起,我不记得我尝试过哪些sed命令,但是sed对Unicode块的支持似乎没有比grep更好。)

最后,我尝试了perl(v5.16.3):

 perl -ne 'print unless /[\u1100-\u11ff]/'

这至少成功地消除了Jamo线,同时保留了Hangul Syllable线,但它也消除了ASCII线,我不想这样做。我也会想到其中一个ff。会工作:

perl -ne 'print unless /\p{InHangul_Jamo}/'
perl -ne 'print unless /\p{Block: Hangul_Jamo}/'

但似乎都没有任何效果。 (Afaik,我不应该在.*的每一边都有\p{...},但我也试过了;没有运气。)

区域设置:如果重要,我有LANG=en_US.UTF-8

我确信我可以用Python做到这一点,但我想理解为什么grep和perl似乎都不起作用,因为它们会更简单。 (如果我对Gnu实用程序的Unicode支持很差,那么为什么......以及什么时候它将被修复。它不像Unicode是新的!)当然我意识到问题可能是我不是当我尝试时,我的嘴巴正确,但如果是这样,grep至少可以获得更好的Unicode使用文档。现在,grep -P的文档说“这是高度实验性的,grep -P可能会警告未实现的功能。”它似乎一直都是这样。

1 个答案:

答案 0 :(得分:2)

解码输入,编码输出。如果有问题的编码是UTF-8,命令行开关-CSD将会有用。

perl -CSD -ne'print if !/\p{Block: Hangul_Jamo}/'
perl -CSD -ne'print if !/\p{Block: Jamo}/'
perl -CSD -ne'print if !/\p{Blk=Jamo}/'
perl -CSD -ne'print if !/\p{InJamo}/'
perl -CSD -ne'print if !/[\N{U+1100}-\N{U+11FF}]/'
perl -CSD -ne'print if !/[\x{1100}-\x{11FF}]/'
grep -vP '[\x{1100}-\x{11FF}]'

您可能希望添加Hangul_Jamo_Extended_AHangul_Jamo_Extended_BHangul_Compatibility_Jamo块。

perl -CSD -ne'print if !/[\p{Block: Hangul_Jamo}\p{Block: Hangul_Jamo_Extended_A}\p{Block: Hangul_Jamo_Extended_B}\p{Block: Hangul_Compatibility_Jamo}]/'
perl -CSD -ne'print if !/[\p{Block: Jamo}\p{Block: JamoExtA}\p{Block: JamoExtB}\p{Block: CompatJamo}]/'
perl -CSD -ne'print if !/[\p{Blk=Jamo}\p{Blk=JamoExtA}\p{Blk=JamoExtB}\p{Blk=CompatJamo}]/'
perl -CSD -ne'print if !/[\p{InJamo}\p{InJamoExtA}\p{InJamoExtB}\p{InCompatJamo}]/'
perl -CSD -ne'print if !/[\N{U+1100}-\N{U+11FF}\N{U+A960}-\N{U+A97F}\N{U+D7B0}-\N{U+D7FF}\N{U+3130}-\N{U+318F}]/'
perl -CSD -ne'print if !/[\x{1100}-\x{11FF}\x{A960}-\x{A97F}\x{D7B0}-\x{D7FF}\x{3130}-\x{318F}]/'
grep -vP '[\x{1100}-\x{11FF}\x{A960}-\x{A97F}\x{D7B0}-\x{D7FF}\x{3130}-\x{318F}]'

让我们看看你失败的尝试。

  •   

    grep -Pv '[\x{1100}-\x{11FF}]'

    实际上,这个应该有效,而且对我有用。

    $ perl -CSD -e'print "abc\nd\x{1100}f\nghi\n"' | od -t x1
    0000000 61 62 63 0a 64 e1 84 80 66 0a 67 68 69 0a
    0000016
    
    $ perl -CSD -e'print "abc\nd\x{1100}f\nghi\n"' | grep -Pv '[\x{1100}-\x{11FF}]'
    abc
    ghi
    
    $ grep --version | head -1
    grep (GNU grep) 2.16
    

    我确实在使用grep (GNU grep) 2.10的旧计算机上收到了您的错误。

  •   

    perl -ne'print unless /\p{Block: Hangul_Jamo}/'

    你没有从/\p{Block: Hangul_Jamo}/获得任何匹配,因为你匹配编码文本(UTF-8字节,00..FF范围内的字符)而不是解码文本(Unicode代码点,字符)在00000..10FFFF范围内。

  •   

    perl -ne 'print unless /\p{InHangul_Jamo}/'

    \p{Block: X}\p{Blk=X}\p{InX}相同。

  •   

    perl -ne'print unless /[\x{1100}-\x{11FF}]/'

    [\x{1100}-\x{11FF}]相当于\p{Block: Hangul_Jamo}

  •   

    perl -ne'print unless /[\u1100-\u11ff]/'

    自从\u以来,双引号字符串文字中的匹配太多,而正则表达式模式文字则引发了下一个字符。 (例如"\uxyx"相当于"Xyz"。)

    因此,[\u1100-\u11ff]相当于[01f]