【问题标题】:How can I capture multiple matches from the same Perl regex?如何从同一个 Perl 正则表达式中捕获多个匹配项?
【发布时间】:2011-02-22 11:53:28
【问题描述】:

我正在尝试解析单个字符串并从具有相同正则表达式条件的同一字符串中获取多个数据块。我正在解析一个静态的 HTML 文档(出于未公开的原因,我不能使用 HTML 解析器来完成这项工作。)我有一个看起来像这样的表达式:

$string =~ /\<img\ssrc\="(.*)"/;

我想得到 1 美元的价值。但是,在一个字符串中,有很多这样的img标签,所以我需要一个返回数组(@1?)这样的东西这可能吗?

【问题讨论】:

  • 在这些情况下,我会在我的正则表达式中添加更多上下文以获取我想要的特定图像标签。也就是说,当我不想使用 HTML 解析器来做正确的事情时,比如 HTML::SimpleLinkExtor,它会为您提取所有 img src 值。

标签: regex perl string


【解决方案1】:

作为 Jim 的回答,使用 /g 修饰符(在列表上下文或循环中)。

但要小心贪婪,您不希望 .* 匹配超出必要的范围(并且不要逃避

while($string =~ /<img\s+src="(.*?)"/g ) {
  ...
} 

【讨论】:

  • 太棒了,是的,我遇到了贪婪的问题,那个?修复。说,你会碰巧知道需要在正则表达式中转义的字符列表吗?我基本上逃避了几乎所有事情,因为我不知道更好:P
  • 通常您必须转义元字符和量词。在 Perl 中,你有:Metacharacters: . $ ^ | () [] \ Quantifiers: * + ? {} 但有一些复杂性 - 特别是在字符类 [] 内部,情况会发生变化。
  • ...但解决贪心问题的更好方法是使用"([^"]*)"。在许多正则表达式引擎中,这会更有效,但更重要的是,它更清楚地说明了您的意图:您想要匹配 " 后跟一些 非双引号 字符,然后是另一个",而不是由任何字符的最短可能序列分隔的两个 " 字符。
  • @Dave:是的,这是指定非贪婪的两种常用方法,最好了解这两种方法并使用更合适的方法。但是(尽管我同意你的在语义上更正确),在这个特定的模式中(以引号结束)它们是完全等价的(在功能上,也许不是速度方面),我的眼睛更清楚一点。跨度>
  • 绝对不是快速的。回溯将强制 /".*?"/ 每次无法满足辅助双引号时重新扫描字符串。例如,针对“abcd”,它必须首先尝试“,然后是”a,然后是“ab,依此类推,直到找到第二个引号。虽然智能正则表达式编译器可能能够优化它(继续扫描直到你到达“),我不会依赖编译器那么聪明。一般来说,避免使用 .* ,除非你真的、真的是认真的。
【解决方案2】:
@list = ($string =~ m/\<img\ssrc\="(.*)"/g);

g 修饰符匹配字符串中的所有出现。列表上下文返回所有匹配项。请参阅perlop 中的 m// 运算符。

【讨论】:

    【解决方案3】:

    您只需要在匹配结束时使用全局修饰符 /g。然后循环 直到没有剩余匹配项

    my @matches;
    while ($string =~ /\<img\ssrc\="(.*)"/g) {
            push(@matches, $1);
    }
    

    【讨论】:

      【解决方案4】:

      使用 /g 修饰符并在左侧列出上下文,如

      @result = $string =~ /\<img\ssrc\="(.*)"/g;
      

      【讨论】:

      • 但是我没有字符串数组,只有一个。我正在尝试从单个字符串中的多个 img 标签中获取单个源,并以数组形式返回。我试过了,但没有返回任何东西。
      • 你认为绑定运算符在做什么? :)
      • 我无意中省略了部分答案。已更正。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 2010-12-03
      • 2014-06-26
      • 1970-01-01
      相关资源
      最近更新 更多