JavaScript正则表达式多次捕获

9

好的,我认为我需要重新发布我的问题,原本是:

Javascript正则表达式多个分组

带有完整的示例。 我有:

        var text = ""+ 
            "<html>                           " +
            "  <head>                         " +
            "  </head>                        " +
            "  <body>                         " +
            "    <g:alert content='alert'/>   " +
            "    <g:alert content='poop'/>    " +
            "  </body>                        " +
            "</html>";

        var regex = /<([a-zA-Z]*?):([a-zA-Z]*?)\s([\s\S]*?)>/m;
        var match = regex.exec( text );
        console.log(match)

console.log的输出结果是:

console.log的输出结果

问题在于我只能得到第一个匹配结果,而无法得到其他的匹配结果。有什么办法可以获取并遍历所有匹配的内容呢?


12
请勿使用正则表达式解析HTML。 - m0skit0
你有更好的想法来实现我尝试做的事情吗?也就是获取<g:alert .../>标记,它真正看起来像<r:method ...或其他任何东西。 - mjs
你想做什么?你需要什么结果,确切地说? - Cerbrus
1
你应该使用DOM函数来实现这个,而不是正则表达式。 - leftclickben
2
基本上,使用正则表达式对于你的意图是错误的,因为你正在处理嵌套结构,即递归。而正则表达式无法做到这一点。为了解释这一点,你首先应该了解有限自动机(这是正则表达式底层的数据结构)除了其所处的状态外没有记忆,并且如果你有任意深度的嵌套,你需要一个任意大的自动机,这与有限自动机的概念相冲突。 - StarPinkER
显示剩余4条评论
2个回答

17

exec 一次只返回一个匹配结果,并将指针设置为该匹配的结尾。因此,如果要获取所有匹配项,请使用 while 循环:

exec 每次只能匹配到第一个结果,如果想要获取所有匹配项,需要使用 while 循环。

while ((match = regex.exec( text )) != null)
{
    console.log(match);
}

要一次性获取所有匹配项,请使用text.match(regex),其中正则表达式指定了g(全局标志)。g标志将使match在字符串中查找正则表达式的所有匹配项,并将所有匹配项返回到数组中。

[编辑] 这就是为什么我的示例中设置了g标志! [/eoe]

var text = ""+ 
           "<html>                           " +
           "  <head>                         " +
           "  </head>                        " +
           "  <body>                         " +
           "    <g:alert content='alert'/>   " +
           "    <g:alert content='poop'/>    " +
           "  </body>                        " +
           "</html>";

// Note the g flag
var regex = /<([a-zA-Z]*?):([a-zA-Z]*?)\s([\s\S]*?)>/gm;

var match = text.match( regex );
console.log(match);

简单测试:

<button onclick="myFunction()">Try it</button>

<script>
function myFunction()
{
var text = ""+ 
           "<html>                           " +
           "  <head>                         " +
           "  </head>                        " +
           "  <body>                         " +
           "    <g:alert content='alert'/>   " +
           "    <g:alert content='poop'/>    " +
           "  </body>                        " +
           "</html>";

// Note the g flag
var regex = /<([a-zA-Z]*?):([a-zA-Z]*?)\s([\s\S]*?)>/gi;

var n = text.match( regex );
alert(n);
}
</script>

工作完美无缺...


听起来很有前途,但不幸的是没有起作用。我已经编辑了你的答案,给你一个完整的例子,展示我尝试过的内容... - mjs
@Hamidam:当然会失败(进入无限循环),因为文本一遍又一遍地匹配,它总是返回第一个项目。你不理解matchexec的区别。 - nhahtdh
@nhahtdh 你说得对.. 它们是不同的... 看起来我需要 g 而不是 m... 我很快会发布最终解决方案.. - mjs
@Hamidam:我编辑了他的帖子。execmatch是不同的。String.match会在下一次调用时忘记所有内容。Regex.exec会记住上次匹配的位置,并从那里继续。 - nhahtdh
@nhahtdh 谢谢。我们中的一些人使用Firebug立即运行JavaScript,而不是创建新页面 ;) http://i.msdn.microsoft.com/ee819093.image001(en-us,MSDN.10).png - mjs
无需创建新页面,只需将代码复制并粘贴到任何在线JavaScript测试引擎(如jsfiddler或w3school的引擎)中即可:http://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_match_regexp2 - itsid

2

以下是有效的方法:

           var text = ""+
            "<html>                           " +
            "  <head>                         " +
            "  </head>                        " +
            "  <body>                         " +
            "    <g:alert content='alert'/>   " +
            "    <g:alert content='poop'/>    " +
            "  </body>                        " +
            "</html>";

        var regex = /<([a-zA-Z]*?):([a-zA-Z]*?)\s([\s\S]*?)>/g;
        var match = null;
        while ( (match = regex.exec( text )) != null  )
            console.log(match)

请注意似乎必须要使用/g

@Adriano,不要审查。我认为我有权表达自己。 - mjs
我想发表一个(或两个、三个……)长评论来回复讨论可能更合适。将来遇到同样问题的人会找到你的答案(干净简洁),如果他们认为它很好,他们会点赞。 - Adriano Repetti

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接