繁体   English   中英

在 Perl 中,如何从正则表达式中获取匹配的子字符串?

[英]In Perl, how can I get the matched substring from a regex?

我的程序读取其他程序的源代码并收集有关使用的 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, ...] )。 我怎样才能获得那个子串?

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

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-多线程构建的 v5.10.0

我更喜欢这个:

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) 如果你对有限的适用性没问题的话,它已经足够好了。

如果它遵循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

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";
}

使用捕获组:

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

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

例子:

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

所以你可以做类似的事情

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

警告:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM