问题: 我有大约 1M 行的文本文件,每行由多个单词组成,有些行包含俄语或阿拉伯语单词(我们称它们为“坏行”),我只想删除这些坏行。其他都是“好线路”。
状况:
- 一些好行中存在非 ASCII 字符,因此仅删除所有非 ASCII 字符并不能解决问题。
- 每条线要么完全坏,要么完全好,所以这实际上让事情变得更容易一些。
所以我想到的解决方案就是:
sort file.txt > sorted.txt
任何以俄语或阿拉伯语开头的内容都将列在最后。然后我会手动检查他们开始的行,然后执行
head -n X sorted.txt > clean.txt
摆脱他们。有没有更优雅的方法来做到这一点?还有什么其他 Unix 工具可以用来完成这个任务。
输入示例:
kedi
cat
кошка
القط
candy
şeker
конфеты
كاندي
çağrı
resumé
期望的输出:
kedi
cat
candy
şeker
çağrı
resumé
答案1
这至少应该适用于您的示例:
$ perl -CS -Mutf8 -lne 's{
(?= [\p{Arabic}\p{Cyrillic}] )
[\p{Arabic}\p{Cyrillic}\p{Common}\p{Inherited}] +
(?<= [\p{Arabic}\p{Cyrillic}] ) }{}xg || print' < file
kedi
cat
candy
şeker
çağrı
resumé
基本思想是使用\p
定义一组代码点,在本例中是阿拉伯语或西里尔语,如果一行匹配,则不会打印。不幸的是,我自己不明白细节,这是由@tchrist在聊天。我建议你在那里阅读他的描述。我现在没有时间破译正则表达式,但一旦我有机会自己理解它,我会立即添加解释。鉴于来源,我假设它比下面我的极简版本更完整、更安全。
我自己理解的一个简化版本是
$ perl -CS -ne '/[\p{Arabic}\p{Cyrillic}]+/ || print' < file
这将打印不包含任何阿拉伯或西里尔字符的所有行仅有的。说明 STDIN、STDOUT 和 STDERR 都是 unicode -CS
。perl
其-ne
含义是“读取每个输入行并应用 给定的脚本-e
。如果该行与 不匹配,则/foo/ || bar
表示执行操作。在这种情况下,如果该行与任何阿拉伯或西里尔字符不匹配,则打印。bar
foo
最后,\p{}
是(来自man perluniprops
):
The Perl regular expression "\p{}" and "\P{}" constructs give access to
most of the Unicode character properties.
这允许您匹配一系列字符,例如阿拉伯语或西里尔语或几乎任何您能想到的其他字符。因此,字符类 [\p{foo}]
将匹配脚本的任何字符foo
。因此,[\p{Arabic}\p{Cyrillic}]
将匹配两个脚本的任何字符。