簡體   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