如何使用sed
或另一种工具来删除所有字符除了特定的多字节范围?
例如,该范围\xd8\xa0 - \xd9\x8a
涵盖以 UTF-8 编码的阿拉伯字符。这是我使用 sed 的天真而充满希望的尝试:
$ echo "Peace be upon you. السلام عليكم. שלום עליכם. Paz sobre vosotros." | sed -n -e 's|[^\xd8\xa0-\xd9\x8a]||p'
sed: -e expression #1, char 25: Invalid range end
理解sed
了多字节字符,应该给我们留下字符串:
السلام عليكم
我考虑过使用iconv
转换为一些阿拉伯语特定的编码,使用sed
,然后转换回来。然而,我正在做的工作并不简单,例如我可能想保留阿拉伯语和希伯来语,因此如果可能的话,我希望始终将所有内容保留为 UTF-8。
如果sed
无法使用多字节字符,我应该使用什么?我一直在寻找sed
解决perl
方案,但没有运气。
请注意,我尝试UTF-8
向问题添加标签,但 unix.SE 将其更改为Unicode
标签。这里没有 Unicode,这些是存储在磁盘上的编码字符串。我认为应该有一个单独的UTF-8
标签。
答案1
您可以使用统一码属性在 Perl 中:
echo "Peace be upon you. السلام عليكم. שלום עליכם. Paz sobre vosotros." \
| perl -CIO -pe 's/\P{Arabic}//g'
-CIO
告诉 Perl 输入和输出是 UTF-8 编码的。\P{...}
是一个负属性匹配,\p{...}
将是一个正属性匹配。
答案2
使用乐(以前称为 Perl_6)
输入示例(OP 的文本保存为单行文件):
~$ cat peace.txt
Peace be upon you. السلام عليكم. שלום עליכם. Paz sobre vosotros.
提取阿拉伯文字:
~$ raku -ne 'put m:g/ <:Script<Arabic>>+ /;' peace.txt
السلام عليكم
提取希伯来语脚本:
~$ raku -ne 'put m:g/ <:Script<Hebrew>>+ /;' peace.txt
שלום עליכם
提取拉丁文字:
~$ raku -ne 'put m:g/ <:Script<Latin>>+ /;' peace.txt
Peace be upon you Paz sobre vosotros
Raku 为 Unicode 提供高级支持,并且它的正则表达式引擎已发展成为一个强大的“语法解析器”。请参阅下面的链接。请注意,如果不匹配,上面的代码将返回空行。如果您只想匹配元素/行,您可以简单地向$/
(或) 匹配变量添加条件调用$<>
:
~$ cat peace2.txt #(remove terminal period from each phrase)
Peace be upon you
السلام عليكم
שלום עליכם
Paz sobre vosotros
~$ raku -ne 'put m:g/ <:Script<Latin>>+ /;' peace2.txt
Peace be upon you
Paz sobre vosotros
~$ raku -ne 'put $/ if m:g/ <:Script<Latin>>+ /;' peace2.txt
Peace be upon you
Paz sobre vosotros
最后,您可以通过插入字符来搜索 Unicode 属性的否定!
。您还可以使用+
和/或从所需的字符类中添加(甚至减去)-
。 [注意:Z
下面的附加正则表达式原子(空格)。为了完整起见,下面的代码显示了+
和!
参数——尽管 a-
在实践中可能有效]:
~$ raku -ne 'put $/ if m:g/ <+:!Script<Latin> + :!Z >+ /' peace2.txt
السلام عليكم
שלום עליכם
https://docs.raku.org/language/unicode
https://docs.raku.org/language/unicode#index-entry-UTF-8_Clean-8
https://stackoverflow.com/a/66540269/7270649