将递归PHP正则表达式转换为JavaScript

时间:2011-11-25 21:24:19

标签: php javascript regex

我需要帮助来在JavaScript中复制这个PHP正则表达式:

#\<code>((?:[^<]|\<(?!/?code>)|(?R))+)\</code>#

除了code标记内的标记外,它会删除所有标记。

2 个答案:

答案 0 :(得分:5)

这是不可能的。

您无法将此正则表达式转换为JavaScript风格,因为它使用JavaScript正则表达式引擎不支持的递归(?R)

我建议采用不同的方法。我假设您要删除尖括号内的所有内容,包括周围的括号,除非在<code>...</code>块中找到这些括号。对?那么,JavaScript正则表达式(它甚至不支持lookbehind断言)可以为你做的最好的事情是:

result = subject.replace(/<(?!\/code)[^<>]*>\s*(?!(?:(?!<code>)[\s\S])*<\/code>)/g, "");

这是做什么的(不幸的是,JavaScript甚至不支持详细的正则表达式;这个正则表达式很难包裹......):

<             # Match a <
(?!/code)     # (unless it's part of a </code> tag)
[^<>]*        # and any number of non-bracket characters
>             # followed by >
\s*           # and any whitespace.
(?!           # Assert that we can't match the following here:
 (?:          # The following expression:
  (?!         # Unless we are right before a
   <code>     # <code> tag
  )           # Then match
  [\s\S]      # any character
 )*           # any number of times
 </code>      # until the next </code> tag
)             # End of lookahead assertion

这确保我们只匹配标记,如果下面的下一个<code> / </code>标记是开始<code>标记,而不是结束</code>标记(或者如果根本没有这样的标签)。

所以它转换

This <b> is bold </b> text, 
but we want <code> these <i> tags <b> here </b> to remain </i> </code> 
while those <b> can be deleted</b>.

This is bold text, 
but we want <code> these <i> tags <b> here </b> to remain </i> </code> 
while those can be deleted.

如果您想要自行删除code标记,也可以使用

result = subject.replace(/<[^<>]*>\s*(?!(?:(?!<code>)[\s\S])*<\/code>)|<code>\s*/g, "");

将给出结果

This is bold text, 
but we want these <i> tags <b> here </b> to remain </i> 
while those can be deleted.

如果code标签可以嵌套,这些正则表达式都不起作用。

答案 1 :(得分:0)

如果你想在JavaScript中这样做,我的猜测是你可能正在一个环境中工作,你已经有了一套完整的HTML解析和遍历工具 - 浏览器DOM。

如果情况确实如此,那么正则表达式不是处理标记的理想工具的一般好建议在这里应用得很多,你可能会考虑做其他事情。

将一个标记片段放入一个可以使用DOM接口操作它的表单非常简单:

var working = document.createElement('div');  //create a new empty element
working.innerHTML = sourceToSanitize;         //put your HTML source inside it
var sanitized = sanitize(working);            //call sanitization function!

现在你只需要一个sanitize函数,你可以在该元素上调用它将遍历DOM树中的每个节点,并返回一个转换后的HTML片段。

这样的事可能有用:

function sanitize(emt) {
    if(emt.nodeType == 3)     // terminal cond #1: just return text nodes
        return emt.textContent;
    if(emt.nodeType != 1)     // terminal cond #2: non-text/element nodes yield null
        return null;
    if(emt.tagName=='code' || emt.tagName=='CODE') //#3: code tags returned untouched
        return outerHTML(emt);

                              // recurse over all child nodes
    var schf = [], // *S*anitized *C*hild *H*TML *F*ragments
        children = emt.childNodes;
    for(var i=0,z=children.length; i<z; i++) 
        schf.push(sanitize(children[i]));
    return schf.join('');     // smoosh results together and serve fresh!
}

function outerHTML(emt) {
    if(emt.outerHTML) return emt.outerHTML;
    var tmp = document.createElement('div');
    tmp.appendChild(emt.cloneNode(true));
    return tmp.innerHTML;
}