如何在bash中将包含非ascii字符的文件拆分为单词?

时间:2014-09-17 19:32:53

标签: bash split non-ascii-characters

例如,我有一个普通文本的文件,例如:

"Word1 Kuͦn, buͤtten; word4:"

我想获得一个每行1个单词的文件,保持点状,然后命令:

,
:
;
Word1
Kuͦn
buͤtten
word4

我使用的代码:

grep -Eo '\w+|[^\w ]' input.txt | sort -f >> output.txt  

这段代码几乎完美无缺,除了一件事:它将diacretical字符与它们所属的字母分开,好像它们是分开的单词:

    ,
    :
    ;
    Word1
    Ku
    ͦ      
    n
    bu 
    ͤ   
    tten
    word4

字母uͦ,uͤ和其他具有相同diacretics的字母不在ASCII表中。如何在不删除或替换这些字符的情况下正确拆分文件?

编辑:

locale输出:

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=

1 个答案:

答案 0 :(得分:4)

不幸的是,U + 366(组合拉丁文小写字母O)不是字母字符。它是一个非间距标记,unicode类别Mn,通常映射到Posix ctype cntrl

粗略地说,字母字母是一个字母字符,可能后跟一个或多个组合字符。如果您有一个实现Unicode常规类别的正则表达式库,则可以将其写为正则表达式模式。 Gnu grep通常使用流行的pcre(Perl兼容的正则表达式)库的接口进行编译,该库具有相当好的Unicode支持。所以,如果你有Gnu grep,那么你很幸运。

要启用“类似perl”的正则表达式,您需要使用grep选项(或-P)调用pgrep。但是,这还不够,因为默认情况下grep将使用8位编码,即使语言环境指定了UTF-8编码。因此,您需要将正则表达式系统置于“UTF-8”模式,以使其识别您的字符编码。

将所有这些放在一起,您最终可能会得到以下内容:

grep -Po '(*UTF8)(\p{L}\p{M}*|\p{N})+|[\p{P}\p{S}]'

-P      patterns are "perl-compatible"
 -o     output each substring matched

(*UTF8) If the pattern starts with exactly this sequence,
        pcre is put into UTF-8 mode.
\p{...} Select a character in a specified Unicode general category
\P{...} Select a character not in a specified Unicode general category
\p{L}   General category L: letters
\p{N}   General category N: numbers
\p{M}   General category M: combining marks
\p{P}   General category P: punctuation
\p{S}   General category S: symbols
\p{L}\p{M}*       A letter possibly followed by various combining marks
\p{L}\p{M}*|\p{N} ... or a number

有关Unicode常规类别和Unicode正则表达式匹配的更多信息,请参阅正则表达式匹配的Unicode Technical Report 18。但请注意,TR中描述的语法是推荐,并且大多数正则表达式库都没有完全实现。特别是,pcre 支持有用的符号\p{L|N}(字母或数字)。相反,您需要使用[\p{L}\p{N}]

有关pcre的文档可能在您的系统上提供(man pcre);如果没有,have a link on me

如果你没有Gnu grep,或者你的版本是在没有pcre支持的情况下编译的,则可以使用perlpython或其他语言正则表达能力。但是,这样做非常困难。经过一些实验,我发现以下Perl咒语似乎有效:

perl -CIO -lne 'print $& while /(\p{L}\p{M}*|\p{N})+|[\p{P}\p{S}]/g'

在这里,-CIO告诉Perl UTF-8中的输入和输出,-nle是标准咒语,意思是“在打印后自动输出新的** l ines”;循环遍历每一个li ** n **输入,** e **在循环中执行以下操作“。