Javascript match()函数返回完全匹配的标记

时间:2011-06-05 08:47:36

标签: javascript regex parsing screen-scraping

console.log( html.match( /<a href="(.*?)">[^<]+<\/a>/g ));

而不仅仅返回网址:

http://google, http://yahoo.com

它将返回整个标记:

<a href="http://google.com">Google.com</a>, <a href="http://yahoo.com">Yahoo.com</a>

为什么会这样?

2 个答案:

答案 0 :(得分:3)

您希望RegExp#exec和循环访问匹配结果的1索引处的元素,而不是String.match。当有String.match标志时,g不返回捕获组,只是每个匹配的索引0处的元素数组,这是整个匹配字符串。 (参见the spec的第15.5.4.10节。)

所以实质上:

var re, match, html;

re = /<a href="(.*?)">[^<]+<\/a>/g;
html = 'Testing <a href="http://yahoo.com">one two three</a> <a href="http://google.com">one two three</a> foo';

re.lastIndex = 0; // Work around literal bug in some implementations
for (match = re.exec(html); match; match = re.exec()) {
  display(match[1]);
}

Live example

但这是使用正则表达式解析HTML。 这里有龙。


更新re龙,这是一个快速列出的东西,将击败这个正则表达式,从我的头顶:

  1. ahref之间只有一个空格以外的任何内容,例如两个空格而不是一个,换行符,class='foo'等。等等。
  2. href属性周围使用单引号而不是双引号。
  3. 根本不使用href属性周围的引号。
  4. href属性后也使用双引号的任何内容,例如:

    <a href="http://google.com" class="foo">
    
  5. 这不是你的正则表达式,只是强调正则表达式无法在他们自己的上可靠地使用来解析HTML。它们可以构成解决方案的一部分,帮助您扫描令牌,但它们无法可靠地完成整个工作。

答案 1 :(得分:3)

虽然确实无法使用正则表达式可靠_ 解析 _ HTML,但这不是OP所要求的。

相反,OP需要一种从HTML文档中提取锚链接的方法,这种方法可以使用正则表达式轻松,令人钦佩地处理。

前一位回应者列出的四个问题:

  1. 锚点部分之间的多个空格
  2. 使用单引号而不是双引号
  3. 根本不使用引号来分隔href属性
  4. 具有除href
  5. 之外的其他前导或尾随属性

    只有数字3会对单个正则表达式解决方案带来严重问题,但也恰好是完全非标准的HTML,它永远不会出现在HTML文档中。 (请注意,如果您发现包含非分隔标记属性的HTML,则会有一个与它们匹配的正则表达式,但我认为它们不值得提取.YMMV - 您的里程可能会有所不同。)

    要使用HTML中的正则表达式提取锚链接(hrefs),您可以使用此正则表达式(以注释形式):

    <          # a literal '<'
    a          # a literal 'a'
    [^>]+?     # one or more chars which are not '>' (non-greedy)
    href=      # literal 'href='
    ('|")      # either a single or double-quote captured into group #1
    ([^\1]+?)  # one or more chars that are not the group #1, captured into group #2
    \1         # whatever capture group #1 matched
    

    ,没有评论,是:

    <a[^>]+?href=('|")([^\1]+?)\1
    

    (请注意,我们不需要匹配任何超过最终分隔符的内容,包括标记的其余部分,因为我们感兴趣的是锚链接。)

    在JavaScript中,假设“source”包含您希望从中提取锚链接的HTML:

    var source='<a href="double-quote test">\n'+
               '<a href=\'single-quote test\'>\n'+
               '<a class="foo" href="leading prop test">\n'+
               '<a    href="trailing prop test"   class="foo">\n'+
               '<a style="bar" link="baz" '+
                    'name="quux" '+
                    'href="multiple prop test" class="foo">\n'+
               '<a class="foo"\n href="inline newline test"\n style="bar"\n />';
    

    ,当打印到控制台时,显示为:

    <a href="double-quote test">
    <a href='single-quote test'>
    <a class="foo" href="leading prop test">
    <a    href="trailing prop test"   class="foo">
    <a style="bar" link="baz" name="quux" href="multiple prop test" class="foo">
    <a class="foo" 
     href="inline newline test"
     style="bar"
     />
    

    你会写下以下内容:

    var RE=new RegExp(/<a[^>]+?href=('|")([^\1]+?)\1/gi),
        match;
    
    while(match=RE.exec(source)) {
        console.log(match[2]);
    }
    

    将以下行打印到控制台:

    double-quote test
    single-quote test
    leading prop test
    trailing prop test
    multiple prop test
    inline newline test
    

    注意:

    1. 在nodejs v0.5.0-pre中测试过的代码,但应该在任何现代JavaScript下运行。

    2. 由于正则表达式使用捕获组#1来记录前导分隔引用,因此生成的链接将显示在捕获组#2中。

    3. 您可能希望使用以下方式验证匹配的存在,类型和长度:

      
      if(match && typeof match === 'object' && match.length > 1) {
          console.log(match[2]);
      }
      
      但它确实不应该是必要的,因为RegExp.exec()在失败时返回'null'。另请注意,正确的匹配类型是“对象”,而不是“数组”。