Perl脚本(运行缓慢)需要一分钟来替换简单的正则表达式

时间:2016-12-02 13:08:37

标签: regex perl

Perl脚本(慢慢地运行)一分钟来替换以下正则表达式:

$str = '<![CDATA[$..$]]>;

我在CDATA中有一个包含<![CDATA[$..$]]>(不少于1000次出现)latex / tex编码的文件。因此,我需要将其更改为注释标记和处理指令,如<!--<![CDATA[--><?processingInstruction $..$?><!--]]>-->

$SqrBrLoopMany = qw/((?:[^\[\]]*(?:{(?:[^\[\]]*(?:{[^\[\]]*})*[^\[\]]*)*})*[^\[\]]*)*)/; # This is for using `\[ <whatever> \]` Square bracket.

$str=~s/(\<\!\[CDATA\[)$SqrBrLoopMany(\]\]>)/<\!\-\-$1\-\-><\?processingInstruction $2\?><\!\-\-$3\-\->/sg;

我正在做的上述正则表达式,但脚本需要一分钟来替换输出。

输出应为:

<!--<![CDATA[--><?processingInstruction $..$?><!--]]>-->

如果有人帮助解决这个问题,我们将不胜感激。

2 个答案:

答案 0 :(得分:1)

最简单:

s/<!\[CDATA\[(.*?)]]>/<!--<![CDATA[--><?processingInstruction $1?><!--]]>-->/sg

CDATA不能包含任何嵌套结构,因此模式只会查找起始<![CDATA[和最接近的结尾]]>,并匹配其间的所有内容。

模式运行缓慢的原因是因为您在大括号[^\[\]]之间匹配非括号({ ... })。如果CDATA部分包含不属于结尾[的{​​{1}}或],则会失败并尝试依次回溯每个]]>,从而导致quintic (O(x 5 ))执行时间。

如果需要平衡方括号以使其匹配,则可以执行

[^\[\]]*

s/<!\[CDATA\[(([^][]|\[(?2)*?])*?)]]>/<!--<![CDATA[--><?processingInstruction $1?><!--]]>-->/sg 将再次递归匹配第二个子模式/捕获组。这应该适用于基于Perl和PCRE的正则表达式引擎。

演示:https://regex101.com/r/LmClY9/2

答案 1 :(得分:0)

感谢Markus Jarderot给出了解决方法/答案:

$str=~s/(\<\!\[CDATA\[)([^\]\]>]*)(\]\]>)/<\!\-\-$1\-\-><\?xmltex $2\?><\!\-\-$3\-\->/sg;

<!\[CDATA\[(.*?)]]> Instead of <!\[CDATA\[([^\]\]>]*)]]>