如何使用Perl从单个字符串中捕获子表达式的多个匹配项?

时间:2014-11-20 03:12:27

标签: regex perl capture-group

我目前有以下正则表达式:

^\s*(.+)(?:[-\._ ]+)(\d+)\s*[xX]\s*(\d+)

这将匹配show_3x01_ep. name并检索show301。我想扩展它,以便可以捕获多个剧集。例如:

 show _3x01_3x02 ep. name

应该返回:

show, 3, 01, 3, 02

有人可以向我解释如何做到这一点吗?

3 个答案:

答案 0 :(得分:1)

你对正则表达式的期望过高。最简单的方法是分两步完成。

首先请注意,在您的示例中匹配(.+)的{​​{1}}过于笼统。如果您将模式应用于show,那么您将得到show _3x01_3x02 ep. name - 带有尾随空格 - 因为以下show(不需要转义点或包含字符类[-._ ]+)只对一个字符感到满意。

这会按照你的要求行事。它找到第一个字母字符串,然后找到由单个(?: ... )表示的所有数字字符串对。

x

<强>输出

use strict;
use warnings;

my $s = 'show _3x01_3x02 ep. name';

if ( my ($prefix) = $s =~ /([a-z]+)/i ) {
  print "$prefix\n";
  print "$1 $2\n" while $s =~ /(\d+)x(\d+)/g;
}

答案 1 :(得分:0)

使用Perl的 g 修饰符

您可以使用Perl的 g 正则表达式修饰符在字符串中多次扫描图案。然后,您可以将这些匹配保存到列表中,然后对该列表或其各个元素执行某些操作。例如:

$ echo 'show _3x01_3x02 ep.name' |
      perl -ne '@words = ($_ =~ /\A(.*?)(?=\d)|(\d+)x(\d+)/g);
                @words = grep { $_ ne "" } @words;
                while (my $idx = each @words) {
                    @words[$idx] =~ s/^\s+|\s+\b|_//g;
                };
                print join(", ", @words), "\n"'
show, 3, 01, 3, 02

答案 2 :(得分:-1)

在Ruby中使用字符串#scan

您的文件名不一致,因此您可能最好扫描已知模式然后进行清理。我已经provided a Perl solution,但提供此Ruby解决方案作为替代方案。例如:

str = 'show _3x01_3x02 ep. name'
str.scan(/\A(.*?)(?=\d)|(\d+)x(\d+)/).
    flatten.compact.map { |e| e.gsub(?_, ' ').strip }
#=> ["show", "3", "01", "3", "02"]

这一行代码中有很多内容,但它应该很容易理解。代码将:

  1. 匹配从字符串开头到第一个数字的所有内容作为节目名称。
  2. 匹配它可以找到的所有季节/剧集对。
  3. 将所有匹配作为数组返回。
  4. 展平由捕获组创建的嵌套数组,并丢弃nils。
  5. 在数组的每个成员中用空格替换下划线。
  6. 从数组的每个成员中删除任何周围的空格。
  7. 返回阵列。
  8. 正则表达式本身与Perl兼容,但其余的逻辑依赖于Ruby的String#scan和其他可能无法直接映射到Perl的内部结构。 YMMV。