【问题标题】:Regex for nested values嵌套值的正则表达式
【发布时间】:2011-07-18 12:01:44
【问题描述】:

我想要一个可以忽略嵌套匹配的正则表达式

我的意思是,例如:

/*asdasdasd /* asdasdsa */ qweqweqwe */

将第一个“/*”与最后一个“*/”匹配,而不是停止到第一个“*/”

谢谢...

【问题讨论】:

  • 当它们在带引号的字符串中时?即在混合物中添加了一种全新的成分。
  • 你不能用纯正则表达式解析无限嵌套。
  • @SLaks 当我试图匹配 */ 我得到第一个,但我想要最后一个。
  • "/*asdasdasd /* asdasdsa */ qweqweqwe */".replace(/\/\*.*\*\//, "t") 将整个字符串替换为t
  • @Radek S:我不关心带引号的字符串。里面会有纯文本!

标签: javascript regex comments nested


【解决方案1】:

RegEx 表达式自然会很贪心,所以你可以直接使用:

\/\*.*\*\/

如果你想让它做你害怕的事情并让 RegEx 变得懒惰并在第一场比赛后停止,你必须添加一个 ? 像:

\/\*.*?\*\/

【讨论】:

  • 但是用点 (.),我只得到一行,正确的想法!如果我有多行, [\w\W]* 是否正确?还是有更好的解决方案?
  • 如果有多个 cmets 与您想在它们之间保留的东西,则不起作用。
【解决方案2】:

正则表达式不能按定义计算嵌套项(尽管实现确实比计算机科学定义更进一步)。

http://en.wikipedia.org/wiki/Regular_expression#Expressive_power_and_compactness

【讨论】:

  • 是的,REGULAR 表达式不能匹配嵌套结构,但 Perl、PHP 和 .NET 正则表达式确实可以。
  • 我基本上知道正则表达式比“正则表达式”更强大,但我当然不知道某些实现处理嵌套。这很有趣 :) 另外,在我看来,ridgerunner 的答案是最正确的。
【解决方案3】:

如果文本只有一个嵌套注释,则到目前为止提供的解决方案都可以正常工作。但是,正如 LHMathies 所指出的,如果文本中包含多个您想要保留在它们之间的内容的评论,那么这些解决方案就会失败。例如,这里有一些测试数据来验证算法是否正常工作:

/* one */
Stuff one
/* two /* three */ two */
Stuff two
/* four */

正确的解决方案将保留其中包含内容的两行。要在 Javascript 中正确处理这种情况,您需要一个匹配最里面的注释的正则表达式(这是最难的部分),然后重复应用它直到所有 cmets 都消失了。这是一个经过测试的函数,它正是这样做的:

function strip_nested_C_comments(text)
{ // Regex to match innermost "C" style comment.
    var re = /\/\*[^*\/]*(?:(?!\/\*|\*\/)[*\/][^*\/]*)*\*\//i;
    // Iterate stripping comments from inside out.
    while (text.search(re) != -1) {
        text = text.replace(re, '');
    }
    return text;
}

编辑:提高了不匹配情况的正则表达式效率。 (即将“特殊”从 [\S\s] 更改为 [*\/])。

【讨论】:

    【解决方案4】:

    正则表达式不擅长处理嵌套值,因为您描述的不是“regular language

    但是正则表达式自然是贪婪的。这意味着 * 和 + 量词默认情况下它们将完全按照您的要求进行

    var data = "/*asdasdasd /* asdasdsa */ qweqweqwe */";
    data = data.replace( /\/\*.*\*\//, '' );
    alert( 'Data: ' + data );
    

    【讨论】:

    • 如果有多个 cmets 与您想在它们之间保留的东西,则不起作用。
    【解决方案5】:

    我猜你真的想要从字符串中删除或处理正确嵌套的 cmets 的东西,即使有多个 - 给出“贪婪”正则表达式的答案将从第一个 /* 到最后一个*/:在keep /* comment */ keep /* comment */ keep 这样的字符串中,他们会将中间的keep 视为评论的一部分。

    简短的回答是 Javascript RegExps 不够强大,您需要递归模式。 (也称为regexps can't count)。

    但是,如果您只想删除 cmets,您可以使用循环并首先删除最里面的那些(使用来自@mVChr 的非贪婪正则表达式,修改为匹配最后一个可能的起始分隔符而不是第一个):

    var re = /(.*)\/\*.*?\*\//; while (re.test(string)) string.replace(re, '$1')
    

    可以这么说,这会将(嵌套级别的)计数移出正则表达式并进入循环。 (我没有在正则表达式上放置g 标志,因为我不确定在循环中的两个地方使用这样的正则表达式时会产生什么副作用。无论如何,循环都会负责查找所有出现的事件)。

    【讨论】:

    • 您的想法是正确的,但不幸的是,您的正则表达式与“最内层”注释不完全匹配。请参阅我对正则表达式的回答(事实证明这不是那么简单!)
    • @ridgerunner:你说的很对,\/\*.*?\*\/ 将匹配外部 /* 而不是内部。但是,如果您添加多行标志,它非常适合匹配 C89 cmets。我正在修复答案以使 /* 尽可能晚地匹配 - 然后它甚至可以与贪婪匹配一起使用,仍然在分隔符之间使用简单的 .*
    • 嗯,不完全是,仍然需要非贪婪匹配。
    • 正如我所说,匹配“最内层”注释的正则表达式并非易事。请参阅我的答案以获取正确工作的答案。它还实现了 Friedl 的“展开循环”结构以提高速度。
    • @ridgerunner:你有一个具体的例子,我的正则表达式(未捕获的部分)与最右边的最里面的评论不匹配? (忽略多行问题)。
    猜你喜欢
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多