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

kat*_*een 10 regex perl

我的程序读取其他程序的源代码并收集有关使用过的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";
...
Run Code Online (Sandbox Code Playgroud)

结果打印打印整行而不是我期望的子串.我尝试了不同的方法,但我很少使用Perl,可能会产生基本的概念错误.(行中tablename的位置不固定.另一个问题是多次出现,即[... SELECT*FROM AADTTAB,BBDTTAB,...]).我怎样才能获得那个子串?

Jes*_*ogt 20

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

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

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

# 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";
  }
}
Run Code Online (Sandbox Code Playgroud)

结果:

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

输出:

AADTTAB
BBDTTAB
Run Code Online (Sandbox Code Playgroud)

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

输出:

AADTTAB
Run Code Online (Sandbox Code Playgroud)

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


Axe*_*man 17

我更喜欢这个:

my ( $table_name ) = $line =~ m/(\S{2}DT\S{3})/i;
Run Code Online (Sandbox Code Playgroud)

这个

  1. 扫描$line并捕获与模式对应的文本
  2. 将捕获(1)的"全部"返回到另一侧的"列表".

这个伪列表上下文是我们如何捕获列表中的第一个项目.它的传递方式与传递给子程序的参数完全相同.

my ( $first, $second, @rest ) = @_;


my ( $first_capture, $second_capture, @others ) = $feldman =~ /$some_pattern/;
Run Code Online (Sandbox Code Playgroud)

注意::那就是说,你的正则表达式假定文本在很多情况下都有用.没有捕获任何没有dt的表名,就像在7位和4位中一样?它足够好1)快速和脏,2)如果你的适用性有限.


Sin*_*nür 8

如果跟随,那么匹配模式会更好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__
Run Code Online (Sandbox Code Playgroud)

输出:

C:\Temp> s
aadttab
Run Code Online (Sandbox Code Playgroud)

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

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

perldoc perlre.


mle*_*amp 7

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";
}
Run Code Online (Sandbox Code Playgroud)