Sự khác biệt giữa dấu ngoặc vuông và dấu ngoặc trong một regex là gì?


101

Đây là một biểu thức chính quy tôi đã tạo để sử dụng trong JavaScript:

var reg_num = /^(7|8|9)\d{9}$/

Đây là một cái khác do thành viên nhóm của tôi gợi ý.

var reg_num = /^[7|8|9][\d]{9}$/

Quy tắc là xác thực một số điện thoại:

  • Nó chỉ nên có mười số.
  • Số đầu tiên được cho là bất kỳ trong số 7, 8 hoặc 9.

Câu trả lời:


124

Các regex này là tương đương (cho các mục đích phù hợp):

  • /^(7|8|9)\d{9}$/
  • /^[789]\d{9}$/
  • /^[7-9]\d{9}$/

Lời giải thích:

  • (a|b|c)là regex "OR" và có nghĩa là "a hoặc b hoặc c", mặc dù sự hiện diện của dấu ngoặc, cần thiết cho OR, cũng ghi lại chữ số. Để hoàn toàn tương đương, bạn sẽ viết mã (?:7|8|9)để biến nó thành một nhóm không bắt giữ.

  • [abc]là "lớp ký tự" có nghĩa là "bất kỳ ký tự nào từ a, b hoặc c" (một lớp ký tự có thể sử dụng phạm vi, ví dụ [a-d]= [abcd])

Lý do các regex này tương tự nhau là vì một lớp ký tự là viết tắt của một "hoặc" (nhưng chỉ cho các ký tự đơn). Trong một cách thay thế, bạn cũng có thể làm điều gì đó tương tự (abc|def)mà không chuyển sang lớp ký tự.


30
(7|8|9)[789]không tương đương, bởi vì cái đầu tiên là chụp, cái sau thì không. (?:7|8|9)mặt khác sẽ tương đương (tôi đoán bạn biết điều đó tất nhiên ...).
hochl

Tôi nhìn thấy regex này: [<<|>>|\]\]|\[\[]. Vì bối cảnh, tôi biết rằng regex đang cố gắng so khớp <<hoặc >>hoặc [[hoặc ]]. Nhưng từ những gì bạn đã nói, nó phải khớp <hoặc >hoặc [hoặc ]. Nếu bạn sử dụng |giữa [], các dấu ngoặc có hoạt động khác nhau không?
Daniel Kaplan

1
@DanielKaplan không sử dụng |trong một lớp ký tự [...], trừ khi bạn muốn khớp chính ký tự ống dẫn. Ngoài ra, việc sao chép các ký tự trong một lớp ký tự cũng không ảnh hưởng gì - một lớp ký tự là một danh sách các ký tự và sẽ khớp chính xác với một trong số chúng. Tôi đoán là bạn muốn một nhóm sử dụng dấu ngoặc tròn bình thường:(<<|>>|\]\]|\[\[)
Bohemian

57

Lời khuyên của nhóm bạn gần như đúng, ngoại trừ lỗi đã mắc phải. Một khi bạn tìm ra lý do tại sao, bạn sẽ không bao giờ quên nó. Hãy xem sai lầm này.

/^(7|8|9)\d{9}$/

Điều này làm gì:

  • ^$biểu thị các kết quả phù hợp được cố định, điều này khẳng định rằng chất phụ ở giữa các điểm neo này là toàn bộ kết quả phù hợp. Chuỗi sẽ chỉ khớp nếu chất con phù hợp với toàn bộ chuỗi, không chỉ một phần.
  • ()biểu thị một nhóm bắt .
  • 7|8|9biểu thị phù hợp với một trong hai 7, 8hoặc 9. Nó thực hiện điều này với sự luân phiên , đó là những gì người vận hành đường ống |làm - luân phiên giữa các lần thay đổi. Điều này cản trở giữa các lần thay đổi: Nếu lần thay thế đầu tiên không được khớp, động cơ phải quay lại trước khi vị trí con trỏ di chuyển trong khi khớp của lần thay thế, để tiếp tục khớp với lần thay thế tiếp theo; Trong khi lớp nhân vật có thể thăng tiến tuần tự. Xem kết quả phù hợp này trên công cụ regex đã tắt tối ưu hóa:
Pattern: (r|f)at
Match string: carat

luân phiên

Pattern: [rf]at
Match string: carat

lớp học

  • \d{9}khớp với chín chữ số. \dlà một siêu ký tự viết tắt, khớp với bất kỳ chữ số nào.
/^[7|8|9][\d]{9}$/

Nhìn vào những gì nó làm:

  • ^và cũng $biểu thị các kết quả phù hợp.
  • [7|8|9]là một lớp nhân vật . Bất kỳ ký tự từ danh sách 7, |, 8, |, hoặc 9có thể được xuất hiện, do đó |đã được bổ sung vào không chính xác. Điều này phù hợp mà không có backtracking.
  • [\d]là một lớp nhân vật sống trong siêu ký tự \d. Nhân tiện, việc kết hợp sử dụng một lớp ký tự và một siêu ký tự là một ý tưởng tồi, vì lớp trừu tượng có thể làm chậm quá trình khớp, nhưng đây chỉ là chi tiết triển khai và chỉ áp dụng cho một số triển khai regex. JavaScript không phải là một, nhưng nó làm cho subpattern dài hơn một chút.
  • {9} cho biết cấu trúc đơn trước đó được lặp lại tổng cộng chín lần.

Regex tối ưu là /^[789]\d{9}$/, bởi vì việc /^(7|8|9)\d{9}$/thu thập không cần thiết dẫn đến giảm hiệu suất trên hầu hết các triển khai regex (tình cờ là một, xem xét câu hỏi sử dụng từ khóa vartrong mã, đây có thể là JavaScript). Việc sử dụngchạy trên PCRE để đối sánh thai sẽ tối ưu hóa việc thiếu backtracking, tuy nhiên chúng tôi cũng không sử dụng PHP, vì vậy việc sử dụng các lớp []thay vì thay thế |sẽ mang lại phần thưởng hiệu suất vì trận đấu không quay lại và do đó cả hai đều khớp và thất bại nhanh hơn so với việc sử dụng biểu thức chính quy trước đó.


6
không quan tâm, ảnh chụp màn hình đó từ chương trình nào?
Mr Mystery Guest

12

2 ví dụ đầu tiên hoạt động rất khác nhau nếu bạn đang THAY chúng bằng thứ gì đó. Nếu bạn phù hợp với điều này:

str = str.replace(/^(7|8|9)/ig,''); 

bạn sẽ thay thế 7 hoặc 8 hoặc 9 bằng chuỗi trống.

Nếu bạn phù hợp với điều này

str = str.replace(/^[7|8|9]/ig,''); 

bạn sẽ thay thế 7hoặc 8hoặc 9HOẶC THANH CHỨNG !!!! bởi chuỗi rỗng.

Tôi chỉ tìm thấy điều này một cách khó khăn.


6
Chào mừng đến với SO! Thay thế hoặc kết hợp, nó hoàn toàn sai. Rất nhiều người mắc phải sai lầm đó và họ thường bỏ qua - trong nhiều năm, đôi khi - bởi vì các chuỗi đầu vào của họ không bao giờ chứa dấu ngoặc ( |).
Alan Moore
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.