2009-09-18 43 views
12

Hãy xem xét các chuỗi kí tự sau:Làm thế nào tôi có thể trích xuất các chất nền từ một chuỗi trong Perl?

1) Đề án ID: abc-456-hu5t10 (cao ưu tiên) *****

2) Đề án ID: FRT-78f-hj542w (Balanced)

3) Đề án ID: 23F-f974-nm54w (siêu công thức chạy) *****

01.

và cứ như vậy ở định dạng trên - các phần in đậm là những thay đổi trên các chuỗi.

==>Hãy tưởng tượng tôi có nhiều chuỗi định dạng Hiển thị ở trên. Tôi muốn chọn 3 chất nền (Như được trình bày trong phần BOLD bên dưới) từ mỗi chuỗi trên.

  • chuỗi 1 có chứa các giá trị chữ và số (trong ví dụ trên đó là "abc-456-hu5t10")
  • chuỗi con thứ 2 có chứa từ (trong ví dụ trên đó là "ưu tiên cao")
  • chuỗi con thứ 3 chứa * (IF * có mặt ở cuối chuỗi ELSE để nguyên)

Làm cách nào để chọn 3 chất nền này từ mỗi chuỗi được hiển thị ở trên? Tôi biết nó có thể được thực hiện bằng cách sử dụng biểu thức thông thường trong Perl ... Bạn có thể giúp với điều này?

+0

thể chuỗi trong dấu ngoặc đơn thân chứa lồng nhau? –

Trả lời

29

Bạn có thể làm một cái gì đó như thế này:

my $data = <<END; 
1) Scheme ID: abc-456-hu5t10 (High priority) * 
2) Scheme ID: frt-78f-hj542w (Balanced) 
3) Scheme ID: 23f-f974-nm54w (super formula run) * 
END 

foreach (split(/\n/,$data)) { 
    $_ =~ /Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)?/ || next; 
    my ($id,$word,$star) = ($1,$2,$3); 
    print "$id $word $star\n"; 
} 

Điều quan trọng là sự biểu hiện thường xuyên:

Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)? 

nào chia tay như sau.

Các cố định String "Đề án ID:":

Scheme ID: 

Tiếp theo là một hoặc nhiều ký tự a-z, 0-9 hoặc -. Chúng tôi sử dụng các dấu ngoặc để nắm bắt nó như là $ 1:

([a-z0-9-]+) 

Tiếp theo là một hoặc nhiều ký tự khoảng trắng:

\s+ 

Tiếp theo là một dấu ngoặc mở (mà chúng tôi thoát) tiếp theo là bất kỳ số lượng ký tự mà aren không phải là một dấu đóng, và sau đó là một khung đóng (thoát). Chúng tôi sử dụng dấu ngoặc unescaped để nắm bắt những lời như $ 2:

\(([^)]+)\) 

Tiếp theo là một số không gian bất kỳ có thể là một *, bị bắt như $ 3:

\s*(\*)? 
2
(\S*)\s*\((.*?)\)\s*(\*?) 


(\S*) picks up anything which is NOT whitespace 
\s*  0 or more whitespace characters 
\(  a literal open parenthesis 
(.*?) anything, non-greedy so stops on first occurrence of... 
\)  a literal close parenthesis 
\s*  0 or more whitespace characters 
(\*?) 0 or 1 occurances of literal * 
+0

\ (([^)]) \) sẽ tốt hơn \ ((. *?) \), Vì nó được đảm bảo dừng ở lần đầu tiên). Các định lượng không tham lam có thể gây ra quá trình backtracking nặng, làm chết hiệu suất. (Không chắc chắn trong trường hợp này, phải thừa nhận, nhưng tránh chúng khi chúng không cần thiết vẫn là một thói quen tốt để trau dồi.) Lớp nhân vật phủ định cũng là một tuyên bố rõ ràng hơn về ý định của bạn - bạn đang tìm kiếm "bất kỳ số nào không) ký tự ", không phải" số nhỏ nhất của bất kỳ ký tự nào cả, theo sau là a), làm cho biểu thức như một kết hợp toàn bộ ". –

3

Bạn có thể sử dụng một biểu thức chính quy như sau:

/([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/ 

Vì vậy, ví dụ:

$s = "abc-456-hu5t10 (High priority) *"; 
$s =~ /([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/; 
print "$1\n$2\n$3\n"; 

in

abc-456-hu5t10 
High priority 
* 
1

Thời gian dài không Perl

while(<STDIN>) { 
    next unless /:\s*(\S+)\s+\(([^\)]+)\)\s*(\*?)/; 
    print "|$1|$2|$3|\n"; 
} 
0

Chuỗi 1:

$input =~ /'^\S+'/; 
$s1 = $&; 

String 2:

$input =~ /\(.*\)/; 
$s2 = $&; 

Chuỗi 3:

$input =~ /\*?$/; 
$s3 = $&; 
1

Vâng, một liner ở đây:

perl -lne 'm|Scheme ID:\s+(.*?)\s+\((.*?)\)\s?(\*)?|g&&print "$1:$2:$3"' file.txt 

Mở rộng thành tập lệnh đơn giản để giải thích mọi thứ tốt hơn một chút:

#!/usr/bin/perl -ln    

#-w : warnings     
#-l : print newline after every print        
#-n : apply script body to stdin or files listed at commandline, dont print $_   

use strict; #always do this.  

my $regex = qr{ # precompile regex         
    Scheme\ ID:  # to match beginning of line.      
    \s+    # 1 or more whitespace        
    (.*?)   # Non greedy match of all characters up to   
    \s+    # 1 or more whitespace        
    \(    # parenthesis literal        
    (.*?)   # non-greedy match to the next      
    \)    # closing literal parenthesis      
    \s*    # 0 or more whitespace (trailing * is optional)  
    (\*)?   # 0 or 1 literal *s         
}x; #x switch allows whitespace in regex to allow documentation. 

#values trapped in $1 $2 $3, so do whatever you need to:    
#Perl lets you use any characters as delimiters, i like pipes because      
#they reduce the amount of escaping when using file paths   
m|$regex| && print "$1 : $2 : $3"; 

#alternatively if(m|$regex|) {doOne($1); doTwo($2) ... }  

Mặc dù nếu nó là bất cứ điều gì khác ngoài định dạng, tôi sẽ thực hiện một vòng lặp chính để xử lý các tệp và xác thịt ra khỏi phần thân của tập lệnh thay vì dựa vào các công tắc dòng lệnh cho vòng lặp.

1

này chỉ đòi hỏi một sự thay đổi nhỏ để last answer tôi:

ngoặc
my ($guid, $scheme, $star) = $line =~ m{ 
    The [ ] Scheme [ ] GUID: [ ] 
    ([a-zA-Z0-9-]+)   #capture the guid 
    [ ] 
    \( (.+) \)    #capture the scheme 
    (?: 
     [ ] 
     ([*])    #capture the star 
    )?      #if it exists 
}x; 
Các vấn đề liên quan