【问题标题】:In Perl, how can I get the matched substring from a regex?在 Perl 中,如何从正则表达式中获取匹配的子字符串?
【发布时间】:2009-07-15 15:13:51
【问题描述】:

我的程序读取其他程序的源代码并收集有关使用的 SQL 查询的信息。我在获取子字符串时遇到问题。

...
$line = <FILE_IN>;
until( ($line =~m/$values_string/i && $line !~m/$rem_string/i) || eof )
{
   if($line =~m/ \S{2}DT\S{3}/i)
   {

   # here I wish to get (only) substring that match to pattern \S{2}DT\S{3} 
   # (7 letter table name) and display it.
      $line =~/\S{2}DT\S{3}/i;
      print $line."\n";
...

结果打印打印整行而不是我期望的子字符串。我尝试了不同的方法,但我很少使用 Perl,并且可能会犯基本概念错误。 (行中表名的位置不固定。另一个问题是多次出现,即[... SELECT * FROM AADTTAB, BBDTTAB, ...] )。如何获取该子字符串?

【问题讨论】:

  • 感谢大家提供快速而多样的方法。我昨天和今天早上都尝试使用它们和/但只有 $& 对我有用。还要感谢(使用严格;使用警告;)向我展示我的即兴风格的线索。今天我也意识到我没有通知我在 Windows 下工作(我的珍珠是:这是 perl,为 MSWin32-x86-multi-thread 构建的 v5.8.7 版权所有 1987-2005,Larry Wall Binary build 813 [148120] 由提供ActiveState www.ActiveState.com 建于 2005 年 6 月 6 日 13:36:37)。再次感谢您。
  • 面对我的“无知是一种幸福”后,我有点恼火,但它促使我......好吧......现在让我知道什么是'捕获组''括号/括号' 的意思是,它确实有效。请不要评论我已经觉得很傻。顺便说一句,有没有人支持全球投票将 perl 重命名为 - 我不知道 - 珍珠? ;)
  • 当拉里·沃尔去寻找名字的时候,已经有一种语言叫珍珠了。

标签: regex perl


【解决方案1】:

使用带括号的分组并存储第一组。

if( $line =~ /(\S{2}DT\S{3})/i )
{
  my $substring = $1;
}

上面的代码修复了提取第一个表名的直接问题。但是,问题还询问如何提取所有表名。所以:

# FROM\s+     match FROM followed by one or more spaces
# (.+?)       match (non-greedy) and capture any character until...
# (?:x|y)     match x OR y - next 2 matches
# [^,]\s+[^,] match non-comma, 1 or more spaces, and non-comma
# \s*;        match 0 or more spaces followed by a semi colon
if( $line =~ /FROM\s+(.+?)(?:[^,]\s+[^,]|\s*;)/i )
{
  # $1 will be table1, table2, table3
  my @tables = split(/\s*,\s*/, $1);
  # delim is a space/comma
  foreach(@tables)
  {
     # $_ = table name
     print $_ . "\n";
  }
}

结果:

如果 $line = "SELECT * FROM AADTTAB, BBDTTAB;"

输出:

AADTTAB
BBDTTAB

如果 $line = "SELECT * FROM AADTTAB;"

输出:

AADTTAB

Perl 版本:为 MSWin32-x86-multi-thread 构建的 v5.10.0

【讨论】:

    【解决方案2】:

    我更喜欢这个:

    my ( $table_name ) = $line =~ m/(\S{2}DT\S{3})/i;
    

    这个

    1. 扫描$line并捕获与模式对应的文本
    2. 将“所有”捕获 (1) 返回到另一侧的“列表”。

    这个伪列表上下文是我们捕获列表中第一项的方式。它与传递给子例程的参数的方式相同。

    my ( $first, $second, @rest ) = @_;
    
    
    my ( $first_capture, $second_capture, @others ) = $feldman =~ /$some_pattern/;
    

    注意::也就是说,您的正则表达式过多地假设文本在少数情况下有用。 没有捕获任何没有 dt 的表名,如 7 个位置中的第 3 和第 4 位? 这对于 1)快速和肮脏的,2)如果你对有限的适用性没问题.

    【讨论】:

    • 它是真正的列表上下文,没有什么是伪的!棘手的事情是使用一个项目的列表。当您想从您正在调用的运算符或子例程中强制执行列表上下文行为时,在单个项目列表中捕获操作结果会非常方便。 my $foo = @bar;my ($foo) = @bar; 有很大的不同,区别可以很方便。
    • 哦,它确实派上用场了。我用它所有的时间。我想“伪”是一种不好的表达方式。我知道一个列表仍然是一个列表,它看起来非常像一个标量——这就是我想要得到的全部。
    【解决方案3】:

    如果它遵循FROM,则匹配模式会更好。我假设表名仅由 ASCII 字母组成。在这种情况下,最好说出你想要的。撇开这两条评论,请注意,在列表上下文中成功捕获正则表达式匹配会返回匹配的子字符串。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my $s = 'select * from aadttab, bbdttab';
    if ( my ($table) = $s =~ /FROM ([A-Z]{2}DT[A-Z]{3})/i ) {
        print $table, "\n";
    }
    __END__
    

    输出:

    C:\Temp> s
    aadttab
    

    根据您系统上perl 的版本,您可以使用命名的捕获组,这可能会使整个内容更易于阅读:

    if ( $s =~ /FROM (?<table>[A-Z]{2}DT[A-Z]{3})/i ) {
        print $+{table}, "\n";
    }
    

    perldoc perlre

    【讨论】:

      【解决方案4】:

      Parens 可以让您将正则表达式的一部分放入特殊变量中:$1、$2、$3... 所以:

      $line = ' abc andtabl 1234';
      if($line =~m/ (\S{2}DT\S{3})/i)   {   
          # here I wish to get (only) substring that match to pattern \S{2}DT\S{3}    
          # (7 letter table name) and display it.      
          print $1."\n";
      }
      

      【讨论】:

        【解决方案5】:

        使用捕获组:

        $line =~ /(\S{2}DT\S{3})/i;
        my $substr = $1;
        

        【讨论】:

        • 在使用匹配变量之前始终检查匹配是否成功。
        【解决方案6】:

        $&amp; 包含最后一个模式匹配的字符串。

        例子:

        $str = "abcdefghijkl";
        $str =~ m/cdefg/;
        print $&;
        # Output: "cdefg"
        

        所以你可以做类似的事情

        if($line =~m/ \S{2}DT\S{3}/i) {
            print $&."\n";
        }
        

        警告:

        如果您在代码中使用$&amp;,它将减慢所有模式匹配。

        【讨论】:

        • 避免使用 $& 和相关的 $` 和 $',它们会导致代码中所有正则表达式的性能下降。请参阅 perlre (perldoc.perl.org/perlre.html) 了解更多信息。
        • 只要在代码中的任何位置提及$&amp;,都会减慢所有正则表达式的速度。是否实际使用该值甚至都没有关系。
        • 在研究过程中,我曾经习惯于评估这种说法。有人检查这种 ($&) 的不良做法有多糟糕吗?高达 10%/30% 并且可以分享结果?
        • 我记得我读到过 $&amp; 计划在未来某个时候被弃用。
        • 我认为在 perl 5.10 中可能有一些改变会降低效果
        猜你喜欢
        • 2012-05-04
        • 1970-01-01
        • 1970-01-01
        • 2011-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-10
        相关资源
        最近更新 更多