Những ký tự đặc biệt phải được thoát trong các biểu thức thông thường?


389

Tôi mệt mỏi vì luôn cố gắng đoán, liệu tôi có nên thoát các ký tự đặc biệt như ' ()[]{}|' v.v. khi sử dụng nhiều triển khai biểu thức chính quy.

Nó khác với, ví dụ, Python, sed, grep, awk, Perl, đổi tên, Apache, find, v.v. Có bộ quy tắc nào cho biết khi nào tôi nên và khi nào không nên thoát khỏi các ký tự đặc biệt không? Có phụ thuộc vào loại regrec, như PCRE, POSIX hoặc regexps mở rộng không?


4
Các thư viện regex tốt có các hàm như " escape()" để cho phép sử dụng các chuỗi tùy ý làm các phần regex.
ivan_pozdeev

2
Bạn có thể sử dụng trình kiểm tra biểu thức Regex trực tuyến như gskinner.com/RegExr (miễn phí). (
Nhập

2
Thoát tất cả các ký tự không chữ và số. giai đoạn = Stage.
Salman von Abbas

2
Câu hỏi này đã được thêm vào Câu hỏi thường gặp về Biểu hiện thường xuyên chồng chéo , trong phần "Khác".
aliteralmind

1
Câu hỏi này đã được thêm vào Câu hỏi thường gặp về Stack Overflow thường xuyên , trong "Chuỗi thoát".
aliteralmind

Câu trả lời:


365

Những nhân vật bạn phải và những gì bạn không được thoát thực sự phụ thuộc vào hương vị regex bạn đang làm việc.

Đối với PCRE và hầu hết các hương vị tương thích Perl khác, hãy thoát khỏi các lớp ký tự bên ngoài này:

.^$*+?()[{\|

và những lớp bên trong nhân vật này:

^-]\

Đối với các biểu thức mở rộng POSIX (ERE), hãy thoát các lớp ký tự bên ngoài này (giống như PCRE):

.^$*+?()[{\|

Thoát khỏi bất kỳ ký tự nào khác là một lỗi với POSIX ERE.

Bên trong các lớp ký tự, dấu gạch chéo ngược là ký tự chữ trong các biểu thức chính quy POSIX. Bạn không thể sử dụng nó để thoát khỏi bất cứ điều gì. Bạn phải sử dụng "vị trí thông minh" nếu bạn muốn bao gồm các siêu ký tự lớp nhân vật dưới dạng chữ. Đặt ^ bất cứ nơi nào ngoại trừ lúc bắt đầu,] ở đầu và - ở đầu hoặc cuối của lớp nhân vật để khớp với các nghĩa đen này, ví dụ:

[]^-]

Trong POSIX biểu thức chính quy cơ bản (BRE), đây là các ký tự đại diện mà bạn cần thoát để loại bỏ ý nghĩa của chúng:

.^$*[\

Việc bỏ dấu ngoặc đơn và dấu ngoặc nhọn trong BREs mang lại cho chúng ý nghĩa đặc biệt mà các phiên bản không thoát của chúng có trong ERE. Một số triển khai (ví dụ GNU) cũng có ý nghĩa đặc biệt đối với các ký tự khác khi thoát, chẳng hạn như \? và +. Thoát một ký tự khác. ^ $ * () {} Thông thường là một lỗi với BREs.

Bên trong các lớp nhân vật, BRE theo quy tắc tương tự như ERE.

Nếu tất cả điều này làm cho đầu bạn quay cuồng, hãy lấy một bản sao của RegexBuddy . Trên tab Tạo, bấm Chèn Mã thông báo, rồi đến Chữ. RegexBuddy sẽ thêm các lối thoát khi cần thiết.


1
Dường như với tôi bạn đã quên "/", cũng cần phải thoát ra bên ngoài một lớp học.
jackthehipster

11
/không phải là một metacharacter trong bất kỳ hương vị biểu thức chính quy nào tôi đã đề cập, vì vậy cú pháp biểu thức chính quy không yêu cầu thoát khỏi nó. Khi một biểu thức chính quy được trích dẫn là một chữ trong ngôn ngữ lập trình, thì các quy tắc định dạng chuỗi hoặc biểu thức chính quy của ngôn ngữ đó có thể yêu cầu /hoặc "hoặc 'được thoát, và thậm chí có thể yêu cầu `\` được thoát gấp đôi.
Jan Goyvaerts 6/2/2015

2
Thế còn đại tràng, ":"? Nó có được trốn thoát bên trong các lớp nhân vật cũng như bên ngoài không? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions nói "PCRE có những quy định phù hợp thoát: bất kỳ ký tự phi-alpha-số có thể được thoát để có nghĩa là giá trị văn chương của nó [...]"
nicolallias

4
CÓ THỂ được trốn thoát không giống như NÊN được trốn thoát. Cú pháp PCRE không bao giờ yêu cầu thoát dấu hai chấm, vì vậy thoát dấu hai chấm chỉ làm cho biểu thức chính tả của bạn khó đọc hơn.
Jan Goyvaerts

1
Đối với ERE không POSIX (cái tôi sử dụng thường xuyên nhất vì nó được Tcl triển khai) thoát khỏi những thứ khác không tạo ra lỗi.
slebetman

61

Hương vị RegEx hiện đại (PCRE)

Bao gồm C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreQuery, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo XRegExp.
Khả năng tương thích PCRE có thể thay đổi

    Bất cứ nơi nào: . ^ $ * + - ? ( ) [ ] { } \ |


Hương vị RegEx kế thừa (BRE / ERE)

Bao gồm awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
Hỗ trợ PCRE có thể được bật trong các phiên bản mới hơn hoặc bằng cách sử dụng tiện ích mở rộng

ERE / awk / egrep / emacs

    Bên ngoài một lớp nhân vật: . ^ $ * + ? ( ) [ { } \ |
    Bên trong một lớp nhân vật:^ - [ ]

BRE / ed / grep / sed

    Bên ngoài một lớp nhân vật: . ^ $ * [ \
    Bên trong một lớp nhân vật: ^ - [ ]
    Đối với nghĩa đen, không thoát: + ? ( ) { } |
    Đối với hành vi regex tiêu chuẩn, thoát:\+ \? \( \) \{ \} \|


Ghi chú

  • Nếu không chắc chắn về một nhân vật cụ thể, nó có thể được thoát như \xFF
  • Các ký tự chữ và số không thể thoát được bằng dấu gạch chéo ngược
  • Các biểu tượng tùy ý có thể được thoát bằng dấu gạch chéo ngược trong PCRE, nhưng không phải BRE / ERE (chúng chỉ phải được thoát khi được yêu cầu). Đối với PCRE ] -chỉ cần thoát trong một lớp nhân vật, nhưng tôi giữ chúng trong một danh sách để đơn giản
  • Các chuỗi biểu thức được trích dẫn cũng phải có các ký tự trích dẫn xung quanh được thoát và thường có dấu gạch chéo ngược được nhân đôi (như "(\")(/)(\\.)"so với /(")(\/)(\.)/trong JavaScript)
  • Ngoài các lối thoát, các triển khai regex khác nhau có thể hỗ trợ các bộ sửa đổi, các lớp ký tự, neo, định lượng và các tính năng khác. Để biết thêm chi tiết, hãy kiểm tra regular-expressions.info , hoặc sử dụng regex101.com để kiểm tra biểu thức của bạn sống

1
Có rất nhiều lỗi trong câu trả lời của bạn, bao gồm nhưng không giới hạn ở: Không có hương vị "hiện đại" nào của bạn yêu cầu -hoặc ]phải thoát ra ngoài các lớp nhân vật. POSIX (BRE / ERE) không có ký tự thoát bên trong các lớp ký tự. Hương vị regex trong RTL của Delphi's thực sự dựa trên PCRE. Python, Ruby và XML có các hương vị riêng gần với PCRE hơn các hương vị POSIX.
Jan Goyvaerts

1
@JanGoyvaerts Cảm ơn bạn đã sửa chữa. Các hương vị bạn đề cập thực sự gần gũi hơn với PCRE. Đối với những người trốn thoát, tôi giữ chúng theo cách đơn giản; dễ nhớ hơn là chỉ trốn thoát mọi nơi hơn một vài ngoại lệ. Người dùng có quyền lực sẽ biết những gì đang xảy ra, nếu họ muốn tránh một vài dấu gạch chéo ngược. Dù sao, tôi đã cập nhật câu trả lời của mình với một vài giải thích mà hy vọng sẽ giải quyết được một số nội dung này.
Beejor

22

Thật không may, thực sự không có một bộ mã thoát vì nó thay đổi dựa trên ngôn ngữ bạn đang sử dụng.

Tuy nhiên, việc giữ một trang như Trang Công cụ Biểu thức Chính quy hoặc Áo choàng Biểu thức Chính quy này có thể giúp bạn nhanh chóng lọc ra mọi thứ.


1
Bảng cheat được thêm vào là quá đơn giản và có một số lỗi rõ ràng. Ví dụ, nó nói \<\>là ranh giới từ, chỉ đúng (AFAIK) trong thư viện regex Boost. Nhưng ở nơi khác nó nói <>là siêu nhân vật và phải được thoát (đến \<\>) để khớp với chúng theo nghĩa đen, điều này không đúng trong bất kỳ hương vị nào
Alan Moore

5

Thật không may, ý nghĩa của những thứ như (và \ (được hoán đổi giữa các biểu thức chính quy của Emacs và hầu hết các kiểu khác. Vì vậy, nếu bạn cố gắng thoát khỏi những điều này, bạn có thể làm ngược lại với những gì bạn muốn.

Vì vậy, bạn thực sự phải biết phong cách bạn đang cố gắng để trích dẫn.


5

POSIX nhận ra nhiều biến thể trên biểu thức chính quy - biểu thức chính quy cơ bản (BRE) và biểu thức chính quy mở rộng (ERE). Và thậm chí sau đó, có những điều kỳ quặc vì những triển khai lịch sử của các tiện ích được chuẩn hóa bởi POSIX.

Không có một quy tắc đơn giản nào khi sử dụng ký hiệu nào, hoặc thậm chí ký hiệu nào mà một lệnh đã cho sử dụng.

Hãy xem cuốn sách Làm chủ thường xuyên của Jeff Friedl .


4

Thực sự, không có. có khoảng một nửa triệu cú pháp regex khác nhau; họ dường như đi xuống Perl, EMACS / GNU và AT & T nói chung, nhưng tôi luôn luôn ngạc nhiên.


4

Đôi khi, việc thoát đơn giản là không thể với các ký tự bạn đã liệt kê. Ví dụ: sử dụng dấu gạch chéo ngược để thoát dấu ngoặc sẽ không hoạt động ở phía bên trái của chuỗi thay thế trong sed, cụ thể là

sed -e 's/foo\(bar/something_else/'

Tôi có xu hướng chỉ sử dụng một định nghĩa lớp nhân vật đơn giản để thay thế, vì vậy biểu thức trên trở thành

sed -e 's/foo[(]bar/something_else/'

mà tôi tìm thấy công việc cho hầu hết các triển khai regrec.

Các lớp nhân vật BTW là các thành phần regrec vanilla đẹp, vì vậy chúng có xu hướng hoạt động trong hầu hết các tình huống mà bạn cần các ký tự thoát trong regexps.

Chỉnh sửa: Sau khi nhận xét bên dưới, chỉ cần nghĩ rằng tôi đã đề cập đến thực tế là bạn cũng phải xem xét sự khác biệt giữa automata trạng thái hữu hạn và automata trạng thái không hữu hạn khi xem xét hành vi của đánh giá regrec.

Bạn có thể muốn xem "cuốn sách bóng sáng" hay còn gọi là Perl hiệu quả ( liên kết Amazon được khử trùng ), cụ thể là chương về các biểu thức thông thường, để cảm nhận sự khác biệt về các loại đánh giá động cơ regrec.

Không phải tất cả thế giới là một PCRE!

Dù sao đi nữa, regrec rất khó so với SNOBOL ! Bây giờ đó là một khóa học lập trình thú vị! Cùng với một trên Simula .

Ah niềm vui học tập tại UNSW vào cuối những năm 70! (-:


'sed' là một lệnh mà đơn giản '(' không đặc biệt nhưng '\ (' là đặc biệt; ngược lại, PCRE đảo ngược ý nghĩa, vì vậy '(' là đặc biệt, nhưng '\ (' thì không. OP đang hỏi về.
Jonathan Leffler

sed là một tiện ích * nix sử dụng một trong những bộ đánh giá regrec nguyên thủy nhất. PCRE không tham gia vào tình huống mà tôi mô tả vì nó liên quan đến một lớp tự động hữu hạn (trong) khác với cách nó đánh giá biểu thức chính quy. Tôi nghĩ rằng đề xuất của tôi cho tập hợp cú pháp regrec tối thiểu vẫn được giữ.
Rob Wells

1
Trên hệ thống tuân thủ POSIX, sed sử dụng POSIX BRE, mà tôi trình bày trong câu trả lời của mình. Phiên bản GNU trên hệ thống Linux hiện đại sử dụng POSIX BRE với một vài phần mở rộng.
Jan Goyvaerts

2

Đối với PHP, "luôn luôn an toàn trước một chữ không chữ và số có" \ "để chỉ định rằng nó là viết tắt của chính nó." - http://php.net/manual/en/regapi.reference.escape.php .

Ngoại trừ nếu đó là "hoặc '.: /

Để thoát các biến mẫu regex (hoặc biến một phần) trong PHP, hãy sử dụng preg_quote ()


2

Để biết khi nào và cái gì để thoát mà không cần cố gắng là cần phải hiểu chính xác chuỗi bối cảnh mà chuỗi đi qua. Bạn sẽ chỉ định chuỗi từ phía xa nhất đến đích cuối cùng của nó là bộ nhớ được xử lý bởi mã phân tích cú pháp regrec.

Lưu ý cách xử lý chuỗi trong bộ nhớ: nếu có thể là một chuỗi đơn giản bên trong mã hoặc một chuỗi được nhập vào dòng lệnh, nhưng có thể là một dòng lệnh tương tác hoặc một dòng lệnh được nêu trong tệp tập lệnh shell hoặc bên trong một biến trong bộ nhớ được đề cập bởi mã hoặc một đối số (chuỗi) thông qua đánh giá thêm hoặc một chuỗi chứa mã được tạo động với bất kỳ loại đóng gói nào ...

Mỗi bối cảnh này được gán một số nhân vật có chức năng đặc biệt.

Khi bạn muốn truyền ký tự theo nghĩa đen mà không sử dụng chức năng đặc biệt của nó (cục bộ vào bối cảnh), đó là trường hợp bạn phải thoát khỏi nó, cho bối cảnh tiếp theo ... có thể cần một số ký tự thoát khác có thể cần thêm thoát trong bối cảnh trước (s). Hơn nữa, có thể có những thứ như mã hóa ký tự (khó hiểu nhất là utf-8 vì nó trông giống ASCII cho các ký tự phổ biến, nhưng có thể được tùy ý giải thích ngay cả bởi thiết bị đầu cuối tùy thuộc vào cài đặt của nó để nó có thể hoạt động khác đi, sau đó là thuộc tính mã hóa của HTML / XML, cần phải hiểu chính xác quy trình.

Ví dụ: Một regexp trong dòng lệnh bắt đầu với perl -npe, cần phải được chuyển giao cho một bộ exec cuộc gọi hệ thống kết nối như đường ống xử lý tập tin, mỗi người trong số này gọi hệ thống exec chỉ có một danh sách các đối số được phân cách bằng (không thoát) không gian, và có thể các đường ống (|) và chuyển hướng (> N> N> & M), dấu ngoặc đơn, mở rộng tương tác *?,$(())... (tất cả đây là các ký tự đặc biệt được sử dụng bởi * sh có vẻ như can thiệp vào ký tự của biểu thức chính quy trong ngữ cảnh tiếp theo, nhưng chúng được đánh giá theo thứ tự: trước dòng lệnh. Dòng lệnh được đọc bởi a chương trình như bash / sh / csh / tcsh / zsh, về cơ bản bên trong trích dẫn kép hoặc trích dẫn đơn thì việc thoát đơn giản hơn nhưng không cần thiết phải trích dẫn một chuỗi trong dòng lệnh vì phần lớn khoảng trắng phải được thêm tiền tố vào dấu gạch chéo ngược và trích dẫn là không cần thiết để lại chức năng mở rộng cho các ký tự * và? sẽ ở trong một tệp nguồn. Đối với regrec, có bối cảnh đặt ký tự trong dấu ngoặc vuông [],biểu thức chính quy perl có thể được trích dẫn bởi một tập hợp lớn các ký tự không phải là số alfa (Ví dụ: m // hoặc m: / better / for / path: ...).

Bạn có nhiều chi tiết hơn về các nhân vật trong câu trả lời khác, rất cụ thể cho bối cảnh regrec cuối cùng. Như tôi đã lưu ý, bạn đã đề cập rằng bạn tìm thấy lối thoát regrec bằng các lần thử, đó có thể là do bối cảnh khác nhau có tập hợp ký tự khác nhau làm rối trí nhớ của bạn về các lần thử (dấu gạch chéo ngược là ký tự được sử dụng trong các ngữ cảnh khác nhau để thoát khỏi ký tự nghĩa đen thay vì chức năng của nó ).



0

Đối với Ionic (Bản mô tả), bạn phải tăng gấp đôi dấu gạch chéo để tạo các ký tự. Ví dụ: đây là để khớp với một số ký tự đặc biệt):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Hãy chú ý đến ] [ - _ . /nhân vật này . Họ phải bị chém đôi. Nếu bạn không làm điều đó, bạn sẽ có một lỗi loại trong mã của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.