我有一个文件,其中包含来自 HTML 格式的文本的几个字符串,因此它们中的一些 HTML 序列在控制台界面中看起来不太好。以下是一个例子:
Text1™
[Text®2]
Text:3
我正在尝试删除 & 和 ; 之间的所有内容,以便文本再次可读,如下所示:
Text1
Text2
Text3
我实际上正在尝试使用 sed 删除多余的字符:
sed 's#&*;##g' <file>
问题是它只从文本字符串中删除了 ;。
接下来的问题是,应如何编码正则表达式以删除多余的链:&#[1-9]+;
答案1
你的正则表达式
sed 's#&*;##g' <file>
并没有像你想象的那样。*
字符是一个乘数,表示前一个字符重复 0 次或更多次。前一个字符是&
,因此这将匹配例如&&&;
和;
(&
在之前写了 0 次;
!这是测试用例中匹配的内容),但在本例中不是你想要的。
您需要指定“任何字符”,位于乘数之前,用一个点表示.
。
$ echo 'Text:3' | sed 's#&.*;##g'
Text3
这是第一个问题。第二个是所谓的“贪婪”匹配的概念:sed
将看到第一个&
,然后尝试匹配它能匹配的最大字符串。如果一行中有多个 HTML 实体,这将是一个问题,因为:
$ echo 'Text:3 and some more text å and end' | sed 's#&.*;##g'
Text and end
如果要在sed
上下文中查看修复,可以通过匹配任意数量的“不是 ;
“在结束之前;
执行以下操作:
$ echo 'Text:3 and some more text å and end' | sed 's#&[^;]*;##g'
Text3 and some more text and end
&
您仍然会遇到在文本中合法使用与符号 ( ) 的问题(嗯,&
这是真正的“合法”用法,但现实世界并不总是像理想世界那样可解析)以及匹配过多的问题,但这解释了为什么sed
会出现这样的行为。
答案2
用实际的字符替换代码不是更好吗?
echo 'Text1™
[Text®2]
Text:3' | perl -C -pe 's/&#([^;]*)/chr$1/eg'
输出:
Text1™;
[;Text®;2];
Text:;3