不可能寻找任务。我有一个服务器输出,其中包含<pre>
内的转储。不幸的是,我碰巧转储了一个包含一些html标签的文件。我需要将任何内部</pre>
转换为HTML实体,以便在将数据附加到DOM时不会破坏structire:
<pre>
...
echo '<pre>'
cat gcc.log
echo '</pre>'
...
</pre>
但是有一个明显的规则 - 在echo '
或<pre>
之前始终会有</pre>
。但它可能不完全是echo '</pre>
。
基于此,我构建了非常复杂的正则表达式:
<pre> - The beginning tag
([\s\S]*?) - Any characters including new lines
(?:(echo[^\n]+) - Echo and anything but new line
(<pre>|<\/pre>|<\/xmp>|<xmp>)) - The enclosing tags
([\s\S]*?) - More random characters
<\/pre>
问题是,只要代码中有两个</pre>
,regexp就会匹配第一个,并将第二个视为随机字符 - ([\s\S]*?)
。
如何让正则表达式首先尝试匹配显式字符然后匹配.*?
内容?
哦,我无法在服务器上修复它,真的
答案 0 :(得分:2)
这可能有用(假设标签在引号内并且引号特别平衡):
var html = "<pre>\n ...\n echo '<pre>'\n cat gcc.log\n echo '</pre>'\n ...\n</pre>";
html = html.replace(/(<pre[^>]*>)((?:(?=((["'])(?:(?=(\\.|[^\\"']+|(?!\5)["']))\4)*\5|[^'<]+|<(?!\/pre>)))\3)*)<\/pre>/g,
function(_, g1, g2) {
g2 = g2.replace(/</g, '<');
g2 = g2.replace(/>/g, '>');
return g1 + g2 + '</pre>';
}
);
console.log(html);
此模式使用此技巧模拟原子组:(?>pattern)
=&gt; (?:(?=(pattern))\1)
使用前瞻的内容自然是原子的事实,以避免灾难性的回溯。
答案 1 :(得分:2)
这是一个兼容JavaScript的正则表达式,它匹配一个只有一个嵌套PRE元素的PRE元素(以Python自由空格形式显示,带有大量注释,以便您可以理解它是如何工作的):
re_pre_inside_pre = re.compile(r"""
# Match PRE element containing one nested PRE element.
(<pre\b[^>]*>) # $1: Outer PRE start tag.
( # $2: Outer PRE element contents.
( # $3: Stuff from <PRE> to <PRE>.
[^<]* # (normal*) Zero or more non-tags.
(?: # Begin ((special normal*)*).
< # (special) Any other tags,
(?!\/?pre\b) # but not a <PRE> or </PRE>.
[^<]* # More (normal*).
)* # End ((special normal*)*).
) # End $3: Stuff from <PRE> to <PRE>.
(<pre\b[^>]*>) # $4: Inner PRE start tag.
( # $5: Inner PRE element contents.
[^<]* # (normal*) Zero or more non-tags.
(?: # Begin ((special normal*)*).
< # (special) Any other tags,
(?!\/?pre\b) # but not a <PRE> or </PRE>.
[^<]* # More (normal*).
)* # End ((special normal*)*).
) # End $5: Inner PRE element contents.
(</pre\b\s*>) # $6: Inner PRE end tag.
( # $7: Stuff from </PRE> to </PRE>.
[^<]* # (normal*) Zero or more non-tags.
(?: # Begin ((special normal*)*).
< # (special) Any other tags,
(?!\/?pre\b) # but not a <PRE> or </PRE>.
[^<]* # More (normal*).
)* # End ((special normal*)*).
) # End $7: Stuff from </PRE> to </PRE>.
) # End $2: Outer PRE element contents.
(</pre\b\s*>) # $8: Outer PRE end tag.
""", re.VERBOSE | re.IGNORECASE)
请注意:normal* (special normal*)*
部分是展开的循环 - 效率技术取自Jeffrey Friedl的Mastering Regular Expressions (3rd Edition)。
还请注意捕获组:
$1:
- 外部PRE开始标记
$2:
- 外部PRE
元素的内容
$3:
- 从<PRE>
到<PRE>
的内容
$4:
- 内部PRE开始标记
$5:
- 内部PRE
元素的内容
$6:
- 内部PRE结束标记
$7:
- 从</PRE>
到</PRE>
的内容
$8:
- 外部PRE结束标记。
这是一个经过测试的JavaScript函数,它利用上面的正则表达式将外部PRE内容中的所有尖括号(即组$2
的内容)转换为HTML实体:
// Process PRE element containing one nested PRE element.
function processNestedPRE(text) {
var re_pre_inside_pre = /(<pre\b[^>]*>)(([^<]*(?:<(?!\/?pre\b)[^<]*)*)(<pre\b[^>]*>)([^<]*(?:<(?!\/?pre\b)[^<]*)*)(<\/pre\b\s*>)([^<]*(?:<(?!\/?pre\b)[^<]*)*))(<\/pre\b\s*>)/gi;
return text.replace(re_pre_inside_pre,
function(m0, m1, m2, m3, m4, m5, m6, m7, m8){
// m2 has the outer PRE contents.
// Convert all its <> angle brackets to entities:
m2 = m2.replace(/[<>]/g,
// Use a literal object for conversion.
function(n0){ return {'<': '<', '>': '>'}[n0]; });
// Put humpty dumpty back together again.
return m1 + m2 + m8;
});
}
不知道哪些部分需要验证 - 这就是为什么我已经包含了所有捕获组,以便您可以修改替换功能以仅执行所需的部分。
希望这有帮助。