2012-05-19 52 views
17

Có phương pháp nào trong Java hoặc bất kỳ thư viện nguồn mở nào để thoát (không trích dẫn) một ký tự đặc biệt (ký tự meta), để sử dụng nó như một biểu thức chính quy không?Thoát các ký tự đặc biệt trong Java Biểu thức chính quy

Điều này sẽ rất tiện dụng trong việc tạo động một biểu thức chính quy, mà không phải tự thoát từng ký tự riêng lẻ.

Ví dụ, hãy xem xét một regex đơn giản như \d+\.\d+ phù hợp với con số với một dấu thập phân như 1.2, cũng như đoạn mã sau:

String digit = "d"; 
String point = "."; 
String regex1 = "\\d+\\.\\d+"; 
String regex2 = Pattern.quote(digit + "+" + point + digit + "+"); 

Pattern numbers1 = Pattern.compile(regex1); 
Pattern numbers2 = Pattern.compile(regex2); 

System.out.println("Regex 1: " + regex1); 

if (numbers1.matcher("1.2").matches()) { 
    System.out.println("\tMatch"); 
} else { 
    System.out.println("\tNo match"); 
} 

System.out.println("Regex 2: " + regex2); 

if (numbers2.matcher("1.2").matches()) { 
    System.out.println("\tMatch"); 
} else { 
    System.out.println("\tNo match"); 
} 

Không ngạc nhiên, sản lượng sản xuất bởi các mã trên là:

Regex 1: \d+\.\d+ 
    Match 
Regex 2: \Qd+.d+\E 
    No match 

đó là, regex1 trận 1.2 nhưng regex2 (đó là "động" xây dựng) không (thay vào đó, nó phù hợp với chuỗi chữ d+.d+).

Vì vậy, có phương pháp tự động thoát từng ký tự meta regex không?

Nếu có, chúng ta hãy nói, một escape() phương pháp tĩnh trong java.util.regex.Pattern, đầu ra của

Pattern.escape('.') 

sẽ là chuỗi "\.", nhưng

Pattern.escape(',') 

nên chỉ sản xuất ",", vì nó là không phải là ký tự meta. Tương tự như vậy,

Pattern.escape('d') 

có thể sản xuất "\d", vì 'd' được sử dụng để biểu thị chữ số (mặc dù thoát có thể không có ý nghĩa trong trường hợp này, như 'd' có thể có nghĩa đen 'd', trong đó sẽ không bị hiểu lầm bởi interpeter regex để được cái gì khác, như trường hợp với '.').

+0

Làm thế nào sẽ như một phương pháp xác định sự khác biệt beween a 'd' nghĩa như ký tự meta và 'd' trong văn bản để khớp? ('quote (" d + Dollars? ")' sẽ trở thành '" \\ d + \\ Dollar \\ s? "' trong một phương pháp trích dẫn tầm thường.) – rsp

+0

Đúng, đó là lý do tại sao tôi yêu cầu một phương pháp để thoát nhân vật cá nhân! :-) – PNS

+0

Để chỉ thoát các ký tự riêng lẻ bạn có thể chơi xung quanh với một đường ranh giới từ, giống như: 's/\ b ([dswDSW]) \ b/\\ $ 1/g; ' – rsp

Trả lời

19

Tôi không chắc chắn 100% đây là những gì bạn đang yêu cầu ở đây. Nếu bạn đang tìm kiếm một cách để tạo ra hằng mà bạn có thể sử dụng trong mô hình regex của bạn sau đó chỉ cần thêm vào trước chúng với "\\" sẽ làm việc:

String digit = "\\d"; 

Không có Pattern phương pháp mà tôi biết rằng thực hiện điều này cho bạn. Thật không may, mặc dù có "\\d" cho các chữ số, "\\w" cho các ký tự công việc, v.v. cũng có () để nhóm, +* để lặp lại, v.v. Không có cách phổ biến để xử lý từng phần của cụm từ thông dụng.

Trong bài đăng của bạn, bạn sử dụng Pattern.quote(string) method.Bạn có thể biết rằng đây kết thúc tốt đẹp mẫu của bạn giữa "\\Q""\\E" vì vậy bạn có thể kết hợp một chuỗi thậm chí nếu nó xảy ra để có một nhân vật đặc biệt trong regex nó (+, ., \\d, vv)

+1

Tôi biết về quote() và nếu bạn nhìn vào đầu ra mẫu ở trên nó bao gồm \ Q và \ E. Thật vậy, tôi chỉ đang tìm kiếm một phương pháp để tạo ra phiên bản thoát của một ký tự cho một regex Java. Vì vậy, ví dụ, dấu phẩy thoát sẽ vẫn là dấu phẩy, nhưng khoảng thời gian thoát sẽ trở thành \. và vân vân. – PNS

5

Cách duy nhất mà đối sánh regex biết bạn đang tìm kiếm một chữ số chứ không phải chữ cái d là để thoát khỏi ký tự (\d). Để nhập ký tự thoát regex trong java, bạn cần phải thoát khỏi nó (vì vậy \ trở thành \\). Vì vậy, không có cách nào xung quanh gõ dấu gạch chéo ngược đôi cho ký tự regex đặc biệt.

+0

Chính xác, vì vậy tôi muốn một phương thức có thể thoát khỏi một ký tự thành một chuỗi regex (nghĩa là, không phải chữ). – PNS

+0

Bạn có thể viết phương thức 'escape()' của riêng bạn để thêm tiền tố '" \\ "' vào tham số – Attila

+1

Để rõ ràng về thuật ngữ, thêm dấu gạch chéo ngược vào một ký tự không đặc biệt không được gọi là thoát. Để viết '\ d' không theo bất kỳ cách nào" thoát khỏi ký tự "' d'. Thay vào đó, nó tạo ra một khái niệm hoàn toàn khác biệt, một lớp nhân vật đại diện cho các chữ số. Một ví dụ về thoát là trường hợp thứ hai của bạn, viết '\\' để biểu diễn ký tự gạch chéo. – AndrewF

1

Đồng ý với Gray, như bạn có thể cần mẫu của bạn để có cả hai vị trí (\ [, \]) và các ký tự meta ([,]). vì vậy với một số tiện ích, bạn sẽ có thể thoát khỏi tất cả các ký tự đầu tiên và sau đó bạn có thể thêm các ký tự meta bạn muốn thêm vào cùng một mẫu.

19

tôi viết mô hình này:

Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]"); 

Và sử dụng nó trong phương pháp này:

String escapeSpecialRegexChars(String str) { 

    return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); 
} 

Sau đó, bạn có thể sử dụng nó như thế này, ví dụ:

Pattern toSafePattern(String text) 
{ 
    return Pattern.compile(".*" + escapeSpecialRegexChars(text) + ".*"); 
} 

Chúng tôi cần để làm điều đó bởi vì, sau khi thoát, chúng ta thêm một số biểu thức regex. Nếu không, bạn chỉ có thể sử dụng \Q\E:

Pattern toSafePattern(String text) 
{ 
    return Pattern.compile(".*\\Q" + text + "\\E.*") 
} 
+3

Điều này đã không làm việc cho tôi (ít nhất là trong Scala), nhưng điều này đã làm: '" [\\ {\\} \\ (\\) \\ [\\] \\. \\ + \\ * \\? \\^\\ $ \\\\\\] "' – redent84

+0

Có một danh sách đầy đủ các ký tự đặc biệt ở đây: http://stackoverflow.com/a/27454382/1490986 –

0

sử dụng

pattern.compile("\""); 
String s= p.toString()+"yourcontent"+p.toString(); 

sẽ cho kết quả như yourcontent như là

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