在Linux中使用sed替换ASCII字符

3

我希望在Linux环境下替换文件中的ASCII/英文字符,并保留Unicode字符。

INSERT INTO text (old_id,old_text,old_flags) VALUES (2815829,'[[चित्र:Youth-soccer-indiana.jpg|thumb|300px|right|बचपन का खेल.एसोसिएशन फुटबॉल, ऊपर दिखाया गया है, एक टीम खेल है जो सामाजिक कार्यों को भी प्रदान करता है।]]\n\n\'\'\'खेल\'\'\', कई [[नियमों]] एवं [[रिवाजों]] द्वारा संचालित होने वाली एक [[प्रतियोगी]] गतिविधि है। \'\'खेल\'\' 

我已经尝试过

~$ sed 's/[^\u0900-\u097F]/ /g' hi.text but the range

但是我遇到了以下问题

sed: -e 表达式 #1,字符 23:无效的范围结尾

我也尝试了这个方法,似乎可以工作,但并不完全。

sed 's/[a-zA-Z 0-9`~!@#$%^&*()_+\[\]\\{}|;'\'':",.\/<>?]//g' enwiki-latest-pages-articles-multistream_3.sql  >result.txt

有人能告诉我如何在Unicode范围正则表达式中使用sed吗?

什么是“似乎工作但不完全”的意思? - umläute
1
请简化问题。考虑发布20个混合ASCII和Unicode字符以及这些字符所需的输出。您想删除ASCII,还是如您的标题所说“替换”?一行代码显示一个空格字符,第二行不显示替换字符。祝你好运。 - shellter
是的,我想删除(替换为null)所有ASCII字符,只保留Unicode印地语单词。我尝试的第二个正则表达式保留了一些特殊字符(这是不必要的)。 - gaurus
1
我们已经听到了您的口头描述,但我们需要看到样本!请通过包括良好设计的示例输入(必需的输出)以及您当前的代码和当前输出中的问题和任何错误消息来帮助我们可视化您的问题。请参见https://dev59.com/J4_ea4cB1Zd3GeqPUeiH以获取一个很好的例子(虽然不完全是您感兴趣的领域,但这是一个非常有组织的问题)。祝你好运。 - shellter
输入:INSERT INTO text (old_id, old_text, old_flags) VALUES (2815829,'[[चित्र:Youth-soccer-indiana.jpg|thumb|300px|right|बचपन का खेल.एसोसिएशन फुटबॉल,ऊपर दिखाया गया है,एक टीम खेल है जो सामाजिक कार्यों को भी प्रदान करता है।]]\n\n'''खेल''', कत्पत्ति ==\n"खेल" ("स्पोर्ट") शब्द की [[पुराने फ्रेंच]] शब्द ''देस्पोर्ट (desport)'' से उत्पत्ति हुई है, जिसका अर्थ "अवकाश" है।\n\n== इतिहास ==\n\n[[चित्र:Greek statue discus thrower 2 century aC.jpg|thumb|150px|right|2预期输出:图片:童年足球协会,上面显示了一支团队运动,也提供社交活动。 - gaurus
@user1516947:我已经更新了我的答案,提供了一个Perl实现来完成你的需求。在期望的输出中,我认为你错过了一些符号,比如“.”和“,”以及查询结尾部分提取的印地语单词(“खेल कत्पत्ति खेल स्पोर्ट शब्द की पुराने फ्रेंच शब्द देस्पोर्ट से उत्पत्ति हुई है जिसका अर्थ अवकाश है इतिहास चित्र”)。 - Giuseppe Ricupero
3个回答

4
ASCII码的范围是0到127,包含在此范围内的是0-31和127的控制字符。Unicode编码作为UTF-8使用从128到255的数据字节。由于sed是基于行的,因此换行符(代码9是控制/J)将被特殊处理。您的文件可能包括制表符(代码8)和回车符(代码13),但实际上只关心制表符和可打印ASCII字符。波浪号(~)是代码126(很方便知道的一件事)。所以:
sed -e 's/[ -~\t]/ /g'

其中 \t 是 ASCII 制表符(根据实现方式,你可能需要一个字面制表符),它将删除所有可打印的 ASCII 字符,不会改变换行符和 UTF-8。


2

PERL

如果您不介意使用perl,可以尝试一下这个记忆技巧:

# this version replace each group also newlines
perl -pe 's/[[:ascii:]]/ /g;' filename

更新:使用@user1516947的示例,我稍微修改了Perl解决方案,将多个ASCII字符折叠成一个空格(并删除不需要的前导和尾随空格):

perl -pe 's/[[:ascii:]]+/ /g; s/^\s+|\s+$//g' filename

基于样例输入的命令行使用示例:

echo "INSERT INTO text (old_id,old_text,old_flags) VALUES (2815829,'[[चित्र:Youth-soccer-indiana.jpg|thumb|300px|right|बचपन का खेल.एसोसिएशन फुटबॉल, ऊपर दिखाया गया है, एक टीम खेल है जो सामाजिक कार्यों को भी प्रदान करता है।]]\n\n\'\'\'खेल\'\'\', कत्पत्ति ==\n\"खेल\" (\"स्पोर्ट\") शब्द की [[पुराने फ्रेंच]] शब्द \'\'देस्पोर्ट (desport)\'\' से उत्पत्ति हुई है, जिसका अर्थ \"अवकाश\" है।\n\n== इतिहास ==\n\n[[चित्र:Greek statue discus thrower 2 century aC.jpg|thumb|150px|right|2" | perl -pe 's/[[:ascii:]]+/ /g; s/^\s+|\s+$//g'

输出:

 चित्र बचपन का खेल एसोसिएशन फुटबॉल ऊपर दिखाया गया है एक टीम खेल है जो सामाजिक कार्यों को भी प्रदान करता है। खेल कत्पत्ति खेल स्पोर्ट शब्द की पुराने फ्रेंच शब्द देस्पोर्ट से उत्पत्ति हुई है जिसका अर्थ अवकाश है। इतिहास चित्र

(GNU) SED

在Linux环境中,您需要修改LANG环境变量以使sed范围有效:

# this version does not replace newlines
LANG=C sed 's/[\d0-\d127]/ /g' filename

一种可读性较差的sed版本,它替换了所有换行符(除了一个):
LANG=C sed ':a;N;$!ba;s/[\d0-\d127]/ /g' filename

对于 sed 进行广泛的概括是很危险的,因为即使在 Linux 上,也有多个不兼容的版本。我建议使用 Perl 来保证可移植性。 - tripleee
@tripleee:你说得对,我已经编辑了回复以指定sed实现(gnu)。根据你的经验,这样就足够了吗? - Giuseppe Ricupero
是的,肯定有所改进,但我投票给Thomas的答案 - tripleee
@tripleee Thomas 对 ascii 码有深入的了解,但他的解决方案在 Linux(所请求的环境)中无法正常工作,它也无法去除换行符。 - Giuseppe Ricupero
公正的观点,但我并不完全相信OP 想要压缩换行符。 - tripleee

1
为了去除ASCII字符,您可以在范围内运行它,但是sed会吃掉换行符,所以如果您也想去掉它们,您需要之后使用tr命令。echo -e "hi ☠ \nthere ☠" | LANG=C sed "s/[\x01-\x7F]//g" | tr -d '\n'
☠☠
相反,如果您想要去除Unicode字符,则可以指定Unicode范围:echo -e "hi ☠ \nthere ☠" | LANG=C sed "s/[\x80-\xFF]//g"
hi
there

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接