2009-07-15 29 views
8

Chương trình của tôi đọc các chương trình mã nguồn và thông tin colect khác về các truy vấn SQL đã sử dụng. Tôi gặp vấn đề với việc nhận chuỗi con.Trong Perl, làm thế nào tôi có thể nhận được chuỗi con phù hợp từ một regex?

... 
$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"; 
... 

In kết quả in toàn bộ dòng chứ không phải chuỗi con tôi mong đợi. Tôi đã thử cách tiếp cận khác nhau, nhưng tôi sử dụng Perl hiếm khi và có thể làm cho lỗi khái niệm cơ bản. (vị trí của tablename trong dòng không cố định. Một vấn đề khác là nhiều lần xuất hiện tức là [... SELECT * FROM AADTTAB, BBDTTAB, ...]). Làm thế nào tôi có thể có được chuỗi con?

+0

Cảm ơn tất cả các phương pháp tiếp cận nhanh chóng và khác nhau. Tôi đã cố gắng sử dụng chúng tất cả ngày hôm qua và sáng hôm nay và/nhưng chỉ có $ & làm việc cho tôi. Cũng nhờ (sử dụng nghiêm ngặt; sử dụng cảnh báo;) đầu mối cho thấy tôi phong cách ngẫu hứng của tôi. Hôm nay tôi nhận ra tôi cũng không thông báo rằng tôi làm việc dưới cửa sổ (ngọc trai của tôi là: Đây là perl, v5.8.7 được tạo cho MSWin32-x86-multi-thread Copyright 1987-2005, Larry Wall Binary build 813 [148120] được cung cấp bởi ActiveState www.ActiveState.com Xây dựng ngày 6 tháng 6 năm 2005 13:36:37). Cảm ơn bạn một lần nữa. –

+3

Tôi hơi bực mình sau khi "vô minh là một phúc lạc" trên khuôn mặt của tôi, nhưng nó đẩy tôi đến ... ừm ... hãy nói ngay bây giờ tôi biết những gì 'bắt nhóm' 'paren/dấu ngoặc đơn' và nó thực sự hoạt động. Xin đừng bình luận tôi cảm thấy ngớ ngẩn rồi. BTW, có ai ủng hộ bầu cử toàn cầu để đổi tên perl thành - tôi không biết - ngọc trai? ;) –

+0

Đã có một ngôn ngữ có tên là Pearl, khi Larry Wall tìm kiếm tên. –

Trả lời

8

Sẽ tốt hơn nếu so khớp mẫu nếu nó theo sau FROM. Tôi cho rằng tên bảng chỉ bao gồm các chữ cái ASCII. Trong trường hợp đó, tốt nhất là nói những gì bạn muốn. Với hai nhận xét trên đường đi, lưu ý rằng một trận đấu regex chụp thành công trong ngữ cảnh danh sách trả về (các) chuỗi con phù hợp.

#!/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__ 

Output:

C:\Temp> s 
aadttab 

Tùy thuộc vào phiên bản của perl trên hệ thống của bạn, bạn có thể sử dụng một nhóm chụp tên mà có thể làm cho toàn bộ điều dễ đọc:

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

Xem perldoc perlre.

20

Sử dụng nhóm với dấu ngoặc đơn và lưu trữ nhóm đầu tiên.

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

Mã trên khắc phục sự cố ngay lập tức khi rút tên bảng đầu tiên. Tuy nhiên, câu hỏi cũng hỏi làm thế nào để kéo ra tất cả các tên bảng. Vì vậy:

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

Kết quả:

Nếu $ line = "SELECT * FROM AADTTAB, BBDTTAB;"

Output:

AADTTAB 
BBDTTAB 

Nếu $ line = "SELECT * FROM AADTTAB;"

Output:

AADTTAB 

Perl Version: v5.10.0 xây dựng cho MSWin32-x86-multi-thread

3

Sử dụng một nhóm chụp:

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

Luôn kiểm tra xem trận đấu có thành công hay không trước khi sử dụng các biến phù hợp. –

7

Parens sẽ cho phép bạn lấy phần của regex thành các biến đặc biệt: $ 1, $ 2, $ 3 ... Vì vậy:

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

$& chứa chuỗi khớp với mẫu phù hợp nhất.

Ví dụ:

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

Vì vậy, bạn có thể làm một cái gì đó giống như

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

CẢNH BÁO:

Nếu bạn sử dụng $& trong mã của bạn nó sẽ làm chậm tất cả các mô hình phù hợp.

+1

Tránh sử dụng $ & và $ 'và $ 'có liên quan, chúng gây ra hình phạt về hiệu suất trên tất cả các regex trong mã của bạn. Xem perlre (http://perldoc.perl.org/perlre.html) để biết thêm thông tin. – daotoad

+1

Chỉ cần đề cập đến '$ &', bất kỳ nơi nào trong mã của bạn, sẽ làm chậm tất cả các regex. Nó thậm chí không quan trọng nếu bạn thực sự sử dụng giá trị. –

+0

Nghiên cứu định kỳ tôi đã từng có thói quen đánh giá tuyên bố đó. Có ai kiểm tra việc thực hành xấu ($ &) này có tệ không? Lên đến 10%/30% và có thể chia sẻ kết quả? –

14

tôi thích điều này:

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

này

  1. quét $line và nắm bắt được các văn bản tương ứng với mô hình
  2. lợi nhuận "tất cả" các ảnh chụp (1) vào "danh sách" Mặt khác.

Ngữ cảnh danh sách phát hành này là cách chúng tôi nắm bắt mục đầu tiên trong danh sách. Nó được thực hiện giống như các tham số được truyền cho một chương trình con.

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


my ($first_capture, $second_capture, @others) = $feldman =~ /$some_pattern/; 

LƯU Ý:: Điều đó nói rằng, regex của bạn giả định quá nhiều về văn bản để thể hữu ích trong hơn một số ít các tình huống. Không chụp bất kỳ tên bảng nào không có ở vị trí 3 và 4 trong số 7? Đó là đủ tốt cho 1) nhanh chóng và bẩn, 2) nếu bạn không sao với khả năng ứng dụng hạn chế.

+0

Đó thực sự là danh sách ngữ cảnh, không có gì giả về nó! Điều khó khăn là sử dụng danh sách một mục. Việc nắm bắt các kết quả của một thao tác trong một danh sách mục đơn lẻ có thể rất tiện dụng khi bạn muốn ép buộc hành vi theo ngữ cảnh danh sách từ toán tử hoặc chương trình con mà bạn đang gọi. 'my $ foo = @bar;' rất khác với 'my ($ foo) = @bar;', và sự khác biệt có thể rất tiện dụng. – daotoad

+0

Ồ, nó có ích. Tôi sử dụng nó mọi lúc.Tôi đoán "giả" là một cách xấu để đặt nó. Tôi biết rằng một danh sách một vẫn là một danh sách, nó chỉ trông rất khủng khiếp giống như một quả vô hướng - và đó là tất cả những gì tôi đang cố gắng để có được anyway. – Axeman

Các vấn đề liên quan