2010-04-25 22 views
28

Từ http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html:Whats sự khác biệt giữa z và Z trong một biểu thức chính quy và khi nào và làm thế nào để tôi sử dụng nó?

\Z The end of the input but for the final terminator, if any 
\z The end of the input 

Nhưng có nghĩa gì trong thực tế? Bạn có thể cho tôi một ví dụ khi tôi sử dụng \ Z hoặc \ z không.

Trong thử nghiệm của tôi, tôi nghĩ rằng "StackOverflow\n".matches("StackOverflow\\z") sẽ trả về true và "StackOverflow\n".matches("StackOverflow\\Z") trả về giá trị sai. Nhưng thực ra cả hai đều trở về sai. Sai lầm ở đâu?

Trả lời

22

"Mặc dù \ Z và $ chỉ khớp ở cuối chuỗi (khi tùy chọn cho dấu mũ và đô la để khớp ở ngắt dòng được tắt), có một ngoại lệ. Nếu chuỗi kết thúc bằng một dòng ngắt, sau đó \ Z và $ sẽ khớp tại vị trí trước ngắt dòng đó, chứ không phải ở cuối của chuỗi. "Tăng cường" này được Perl giới thiệu và được sao chép bởi nhiều hương vị regex, bao gồm Java, .NET và Trong Perl, khi đọc một dòng từ một tệp, chuỗi kết quả sẽ kết thúc bằng ngắt dòng. Đọc một dòng từ một tệp có văn bản "joe" dẫn đến chuỗi joe \ n. Khi được áp dụng cho chuỗi này, cả hai^[az] + $ và \ A [az] + \ Z sẽ khớp với joe.

Nếu bạn chỉ muốn khớp ở đầu cuối tuyệt đối của chuỗi, hãy sử dụng \ z (chữ thường z thay vì o f trường hợp trên Z). \ A [a-z] + \ z không khớp với joe \ n. \ Z phù hợp sau khi ngắt dòng, mà không khớp với các lớp nhân vật."

http://www.regular-expressions.info/anchors.html

Con đường tôi đọc "StackOverflow \ n" .matches ("StackOverflow \ z") sẽ trả về false vì mô hình của bạn không bao gồm các dòng mới.

"StackOverflow\n".matches("StackOverflow\\z\\n") => false 
"StackOverflow\n".matches("StackOverflow\\Z\\n") => true 
4

Chỉ cần kiểm tra nó. Dường như khi Matcher.matches() được gọi (như trong mã của bạn, đằng sau hậu trường), \ Z hoạt động như \ z. Tuy nhiên, khi Matcher.find() được gọi, chúng hoạt động khác nhau như mong đợi, sau đây trả về true:

Pattern p = Pattern.compile("StackOverflow\\Z"); 
Matcher m = p.matcher("StackOverflow\n"); 
System.out.println(m.find()); 

và nếu bạn thay \ Z bằng \ z thì trả về false.

Tôi thấy điều này hơi ngạc nhiên ...

+0

Đó là không đáng ngạc nhiên (như tôi đã chỉ hiểu từ câu trả lời được chấp nhận) như '\ z' phù hợp với chỉ tại "thực" kết thúc của chuỗi. Và chuỗi của bạn chưa hoàn thành sau 'StackOverflow' vì dòng mới. – maaartinus

0

Như Eyal đã nói, nó hoạt động cho find() nhưng không phù hợp().

Điều này thực sự có ý nghĩa. Bản thân \ Z tự nó thực sự khớp với vị trí ngay trước terminator cuối cùng, nhưng biểu thức chính quy như một tổng thể không khớp, bởi vì, toàn bộ, nó cần khớp với toàn bộ văn bản được khớp, và không có gì khớp với terminator. (\ Z khớp với vị trí bên phải trước trình kết thúc, không giống nhau.)

Nếu bạn đã làm "StackOverflow\n".matches("StackOverflow\\Z.*") bạn nên ổn.

+0

\ z (chữ thường z) không khớp với dòng mới, nó khớp ở cuối dòng, sau dòng mới. –

+0

@Jakob: Bạn nói đúng. Tôi có nghĩa là \ Z, tất nhiên - đó là một với ý nghĩa đặc biệt. Tôi đã bối rối bởi những từ ngữ trong câu hỏi. Đã sửa lỗi. – Avi

+0

\ Z (chữ hoa) thực sự không khớp ngay trước dòng cuối cùng mới, như được xác định bởi javadocs. Tài liệu perl (http://perldoc.perl.org/perlre.html) làm cho nó rõ ràng hơn: "\ Z \t Chỉ khớp ở cuối chuỗi hoặc trước dòng mới ở cuối" – Avi

0

Tôi nghĩ rằng vấn đề chính ở đây là hành vi bất ngờ của matches(): bất kỳ trận đấu nào cũng phải tiêu thụ toàn bộ chuỗi đầu vào. Cả hai ví dụ của bạn đều thất bại vì các regex không tiêu thụ linefeed ở cuối chuỗi. Các neo không có gì để làm với nó.

Trong hầu hết các ngôn ngữ, một kết hợp regex có thể xảy ra ở mọi nơi, tiêu thụ tất cả, một số hoặc không có chuỗi đầu vào nào. Và Java có một phương thức, Matcher#find(), thực hiện loại kết hợp truyền thống này.Tuy nhiên, kết quả là trái ngược với những gì bạn nói bạn mong đợi:

Pattern.compile("StackOverflow\\z").matcher("StackOverflow\n").find() //false 
Pattern.compile("StackOverflow\\Z").matcher("StackOverflow\n").find() //true 

Trong ví dụ đầu tiên, \z nhu cầu để phù hợp với sự kết thúc của chuỗi, nhưng linefeed dấu là theo cách này. Trong lần thứ hai, các kết quả trùng khớp \Z trước dòng cấp dữ liệu, nằm ở cuối chuỗi.

0

\Z cũng giống như $, nó khớp với phần cuối của chuỗi, cuối chuỗi có thể được theo sau bằng ngắt dòng.

enter image description here enter image description here

\z phù hợp với sự kết thúc của chuỗi, không thể được theo sau bởi ngắt dòng.

enter image description here enter image description here

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