2010-01-04 15 views
10

Giả sử tôi có một tập tin có chứa đường Tôi đang cố gắng để phù hợp với:Làm cách nào để thoát khỏi các ký tự meta khi tôi nội suy một biến trong toán tử đối sánh của Perl?

foo 
quux 
bar 

Trong mã của tôi, tôi có mảng khác:

foo 
baz 
quux 

Hãy nói rằng chúng ta lặp qua các tập tin, gọi nhau phần tử $word và danh sách nội bộ chúng tôi đang kiểm tra, @arr.

if(grep {$_ =~ m/^$word$/i} @arr) 

này hoạt động một cách chính xác, nhưng trong trường hợp nào có thể nơi chúng tôi có một trường hợp thử nghiệm của fo. trong file, các . hoạt động như một nhà điều hành wildcard trong regex, và fo. sau đó phù hợp với foo, đó là không thể chấp nhận .

Điều này tất nhiên vì Perl đang nội suy biến thành một regex.

Câu hỏi đặt ra:

Làm thế nào để buộc Perl để sử dụng biến theo nghĩa đen?

+0

Xem http://stackoverflow.com/questions/1949731/how-can-i-escape-a-literal-string-i- muốn-interpolate-thành-một-regular-expression –

+1

có thể trùng lặp của [Làm thế nào để xử lý các ký tự đặc biệt trong một regex Perl?] (http://stackoverflow.com/questions/576435/how-do-i-handle -special-characters-in-a-perl-regex) – daxim

Trả lời

10

Câu trả lời đúng là - không sử dụng regexps. Tôi không nói regexps là xấu, nhưng sử dụng chúng cho (những gì bằng) kiểm tra bình đẳng đơn giản là quá mức cần thiết.

Sử dụng: grep { lc($_) eq lc($word) } @arr và vui vẻ.

+2

Điểm tốt. Giải pháp regex là phần còn lại của mã cũ và phức tạp hơn. –

30

Sử dụng \Q...\E để thoát khỏi biểu tượng đặc biệt trực tiếp trong chuỗi perl sau khi giá trị biến nội suy:

if(grep {$_ =~ m/^\Q$word\E$/i} @arr) 
+0

Nếu '$ word = 'fo \ E.'' thì sao? –

+0

Sau đó, regexp sẽ giống như "m/^ fo \\ E \. $/I". Xem mô tả siêu ký hiệu '\ Q' trên http://perldoc.perl.org/perlfaq6.html –

+0

Cụ thể, http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators notes rằng '" abc \ Qfoo \ tbar $ s \ Exyz "' tương đương với '" abc ". quotemeta ("foo \ tbar $ s"). "xyz" '. –

15

Từ câu trả lời perlfaq6 's để How do I match a regular expression that's in a variable?:


Chúng tôi không phải mẫu mã hóa cứng vào các nhà điều hành trận đấu (hoặc bất cứ điều gì khác mà làm việc với biểu thức thông thường). Chúng ta có thể đặt mẫu trong một biến để sử dụng sau này.

Toán tử đối sánh là ngữ cảnh trích dẫn kép, vì vậy bạn có thể nội suy biến của bạn giống như chuỗi được trích dẫn kép. Trong trường hợp này, bạn đọc biểu thức chính quy như đầu vào của người dùng và lưu nó trong $ regex. Khi bạn có mẫu trong $ regex, bạn sử dụng biến đó trong toán tử đối sánh.

chomp(my $regex = <STDIN>); 

if($string =~ m/$regex/) { ... } 

Mọi ký tự đặc biệt biểu thức chính quy trong $ regex vẫn còn đặc biệt và mẫu vẫn phải hợp lệ hoặc Perl sẽ khiếu nại. Ví dụ, trong mẫu này có một dấu ngoặc đơn không có dấu ngoặc đơn.

my $regex = "Unmatched (paren"; 

"Two parens to bind them all" =~ m/$regex/; 

Khi Perl biên dịch biểu thức chính quy, nó xử lý dấu ngoặc đơn khi bắt đầu khớp bộ nhớ.Khi không tìm thấy dấu ngoặc đơn đóng, nó sẽ khiếu nại:

Unmatched (in regex; marked by <-- HERE in m/Unmatched (<-- HERE paren/ at script line 3. 

Bạn có thể giải quyết vấn đề này theo nhiều cách tùy theo tình huống của chúng tôi. Trước tiên, nếu bạn không muốn bất kỳ ký tự nào trong chuỗi trở nên đặc biệt, bạn có thể thoát chúng bằng quotemeta trước khi bạn sử dụng chuỗi.

chomp(my $regex = <STDIN>); 
$regex = quotemeta($regex); 

if($string =~ m/$regex/) { ... } 

Bạn cũng có thể thực hiện việc này trực tiếp trong toán tử đối sánh bằng cách sử dụng trình tự \ Q và \ E. \ Q cho Perl biết nơi nào để bắt đầu thoát các ký tự đặc biệt, và \ E cho biết nơi dừng (xem perlop để biết thêm chi tiết).

chomp(my $regex = <STDIN>); 

if($string =~ m/\Q$regex\E/) { ... } 

Cách khác, bạn có thể sử dụng qr //, toán tử trích dẫn biểu thức chính quy (xem chi tiết hơn). Nó trích dẫn và có lẽ biên dịch mẫu, và bạn có thể áp dụng cờ biểu thức chính quy cho mẫu.

chomp(my $input = <STDIN>); 

my $regex = qr/$input/is; 

$string =~ m/$regex/ # same as m/$input/is; 

Bạn cũng có thể bẫy bất kỳ lỗi nào bằng cách gói một khối eval xung quanh toàn bộ.

chomp(my $input = <STDIN>); 

eval { 
    if($string =~ m/\Q$input\E/) { ... } 
    }; 
warn [email protected] if [email protected]; 

Hoặc ...

my $regex = eval { qr/$input/is }; 
if(defined $regex) { 
    $string =~ m/$regex/; 
    } 
else { 
    warn [email protected]; 
    } 
+0

Là eval trong ví dụ mã cuối cùng thứ hai để bẫy lỗi trong "{...}" hoặc có thể có điều gì đó sai trong "if ($ string = ~ m/\ Q $ input \ E /)" quá? –

+0

eval sẽ bắt tất cả các lỗi trong khối của nó, nhưng về mặt câu hỏi này, nó bắt gặp lỗi trong mã rõ ràng mà bạn thấy trong toán tử đối sánh. –

2

Tôi không nghĩ rằng bạn muốn có một regex trong trường hợp này vì bạn không phù hợp với một mô hình. Bạn đang tìm kiếm một chuỗi ký tự theo nghĩa đen mà bạn đã biết. Xây dựng một băm với các giá trị để phù hợp và sử dụng để lọc @arr:

open my $fh, '<', $filename or die "..."; 
my %hash = map { chomp; lc($_), 1 } <$fh>; 

foreach my $item (@arr) 
     { 
     next unless exists $hash{ lc($item) }; 
     print "I matched [$item]\n"; 
     } 
Các vấn đề liên quan