我如何优化这个Perl正则表达式?

时间:2014-06-04 21:17:51

标签: regex perl

我刚才写了这个正则表达式修复了无效/损坏的XML,但它真的很慢,我该怎么做才能让它更快?

s/(.*?>)([^>.]*?&[^\#a].*?)</$1<!\[CDATA\[$2\]\]></ismg;

示例输入数据显示其修复的部分,请注意整个XML包含其他元素并且其中包含更多数据。

<?xml version="1.0" encoding="UTF-8"?><sample>
<test id="123" data="text">&#209;ucastle & Tyne</test>
<test id="123" data="text">Rock & Roll</test>
<test id="123" data="text">Peanut & Butter</test>
<test id="123" data="text">Ice & Cream</test></sample>

示例输出数据:

<?xml version="1.0" encoding="UTF-8"?><sample>
<test id="123" data="text"><![CDATA[&#209;ucastle & Tyne]]></test>
<test id="123" data="text"><![CDATA[Rock & Roll]]></test>
<test id="123" data="text"><![CDATA[Peanut & Butter]]></test>
<test id="123" data="text"><![CDATA[Ice & Cream]]></test></sample>

1 个答案:

答案 0 :(得分:2)

Newcastle <![CDATA[&]]> Tyne或仅Newcastle &amp; Tyne将是等效的。这意味着我们不需要找到文本节点的开头和结尾。我们甚至不需要检查我们是否在文本节点中,因为&也应该在属性值中进行转义。所以你需要的只是:

s/&(?!#|[a-zA-Z]+;)/&amp;/g;

没有回溯。没有捕获。没有什么可以放慢它的速度。

反对您的测试数据:

$ cat >file.xml
<?xml version="1.0" encoding="UTF-8"?><sample>
<test id="123" data="text">Newcastle & Tyne</test>
<test id="123" data="text">Rock & Roll</test>
<test id="123" data="text">Peanut & Butter</test>
<test id="123" data="text">Ice & Cream</test></sample>

$ perl -pe's/&(?!#|[a-zA-Z]+;)/&amp;/g' file.xml
<?xml version="1.0" encoding="UTF-8"?><sample>
<test id="123" data="text">Newcastle &amp; Tyne</test>
<test id="123" data="text">Rock &amp; Roll</test>
<test id="123" data="text">Peanut &amp; Butter</test>
<test id="123" data="text">Ice &amp; Cream</test></sample>

用法:

perl -pe's/&(?!#|[a-zA-Z]+;)/&amp;/g' in.xml >out.xml
perl -i~ -pe's/&(?!#|[a-zA-Z]+;)/&amp;/g' file.xml     # In-place, with backup
perl -i -pe's/&(?!#|[a-zA-Z]+;)/&amp;/g' file.xml      # In-place, no backup