例如,我有一个普通文本的文件,例如:
"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=
答案 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支持的情况下编译的,则可以使用perl
,python
或其他语言正则表达能力。但是,这样做非常困难。经过一些实验,我发现以下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 **在循环中执行以下操作“。