我正在使用 SED 命令从非常大的文本文件中去除外语和其他非键盘字符:
例子:
sed 's/[^a-zA-Z0-9]//g'
上面的命令保留仅包含字母数字字符的任何行,这接近我想要的。问题是它还会删除任何包含常见符号(如 !@#$% 等)的行。我想保留那些。我尝试搜索类似 !-) 之类的 bullion 命令。但我找不到类似的东西。
那么如何从列表中过滤掉阿拉伯语、俄语和无法输入的字符呢? (理想情况下,我不想仅仅对角色进行核攻击,我想对发现它的整行进行核攻击。)
答案1
除了像 Kusalananda 那样使用类之外,您还可以基于 unicode 创建自己的范围。查看这个参考 unicolde 表寻找您喜欢的角色。对于 PCRE,“标准”字符 + TAB 的可能方式是:
grep -P '^[\x{0020}-\x{007e}\x{0008}]{1,}$' file
\x{000A}
请注意,由于 的grep
每行功能(在标准模式下),换行符不作为控制字符包含在内。请考虑 MS 风格的换行符会受到影响并用于\x{000d}\x{000a}
换行符!
答案2
要从文本中删除非 ASCII 字符,请考虑使用tr
如下所示:
LC_ALL=C tr -d -c '[:print:][:cntrl:]' <file.in >file.out
两个 POSIX 字符类[:print:]
和[:cntrl:]
一起涵盖 ASCII 范围内的所有字符,并且-c
我们要求tr
考虑对此的补集,即所有非 ASCII 字符。我们-d
要求tr
删除该补集中的字符。
我们设置LC_ALL
为C
(或POSIX
) 以使[:print:]
字符类仅匹配 ASCII 范围 32 到 126 中的字符。否则它可能会匹配本地语言环境中的可打印字符,例如ä
。该类[:cntrl:]
匹配 0 到 31 和 127 范围内的字符。使用 时LC_ALL=C
,这两个类一起涵盖 0 到 127,即 ASCII 字符。
要删除包含任何非 ASCII 字符的整行:
LC_ALL=C grep -v '[^[:print:][:cntrl:]]' <file.in >file.out
该表达式[^[:print:][:cntrl:]]
将匹配单个非 ASCII 字符。随着-v
我们的询问grep
提取所有行不是匹配该表达式,即提取不包含任何非 ASCII 字符的行。
这两个命令也可以通过以下方式完成sed
:
删除非 ASCII 字符:
LC_ALL=C sed 's/[^[:print:][:cntrl:]]//g' <file.in >file.out
删除包含非 ASCII 字符的行:
LC_ALL=C sed '/[^[:print:][:cntrl:]]/d' <file.in >file.out
请注意,正如 Stéphane 指出的那样在评论中,上述命令将返回一个仅包含 ASCII 字符的文本,或至少编码为 ASCII 的字符(取决于文件的编码)。
一种完全不同的方法是使用iconv
:
iconv -c -t ascii file.in >file.out
这会将文件转换为 ASCII 编码,同时默默地删除所有无法转换的字符(不是行)。