Tại sao phạm vi [01-12] không hoạt động như mong đợi?


91

Tôi đang cố gắng sử dụng mẫu phạm vi [01-12]trong regex để khớp với hai chữ số mm, nhưng điều này không hoạt động như mong đợi.


8
Bạn đang khớp các ký tự , không phải chuỗi ký tự . Về cơ bản, bạn đang khớp với 0, 1 với 1 và 2 (tức là 0, 1 và 2). Hãy xem xét điều này:, điều [a-z0-9]này khớp với tất cả các chữ cái thường và tất cả các chữ số, nhưng chỉ với một ký tự duy nhất.
Lasse V. Karlsen

fwiw Tôi tạo ra một công cụ javascript tạo ra một regex tối ưu hóa cao từ hai đầu vào (min / max) github.com/jonschlinkert/to-regex-range
jonschlinkert

0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] s trong regex biểu thị một lớp ký tự. Nếu không có phạm vi nào được chỉ định, thì nó hoàn toàn là của mọi ký tự.
Badri Gs

Bạn có cần kết hợp nó với regex thuần túy không? Nếu không, bạn có thể: 1.) chỉ cần sử dụng \d+mẫu, 2.) chuyển đổi các chuỗi phù hợp thành các số trong mã của bạn. và sau đó, 3.) kiểm tra dãy số như thế nào if(num >= 0 && num <= 12){ /*do something*/ }. Nó nhanh hơn và linh hoạt hơn rất nhiều.
acegs

Câu trả lời:


192

Có vẻ như bạn đã hiểu sai về cách định nghĩa các lớp ký tự hoạt động trong regex.

Để phù hợp với bất kỳ chuỗi 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, hoặc12 , một cái gì đó giống như tác phẩm này:

0[1-9]|1[0-2]

Người giới thiệu


Giải trình

Bản thân một lớp ký tự sẽ cố gắng khớp một và chính xác một ký tự từ chuỗi đầu vào. [01-12]thực sự xác định [012], một lớp nhân vật phù hợp với một nhân vật từ đầu vào đối với bất kỳ của 3 nhân vật 0, 1hoặc 2.

Các -định nghĩa phạm vi đi từ 1đến 1, mà chỉ bao gồm 1. Mặt khác, một cái gì đó giống như [1-9]bao gồm 1, 2, 3, 4, 5, 6, 7, 8, 9.

Những người mới bắt đầu thường mắc sai lầm khi xác định những thứ như [this|that]. Điều này không "hoạt động". Nhân vật này định nghĩa định nghĩa [this|a], tức là nó phù hợp với một nhân vật từ đầu vào đối với bất kỳ của 6 ký tự t, h, i, s, |hoặc a. Nhiều khả năng (this|that)là những gì được dự định.

Người giới thiệu


Cách xác định phạm vi

Vì vậy, hiển nhiên bây giờ một mẫu như between [24-48] hourskhông "hoạt động". Lớp ký tự trong trường hợp này tương đương với [248].

Nghĩa là, -trong định nghĩa lớp ký tự không xác định phạm vi số trong mẫu. Các công cụ Regex không thực sự "hiểu" các số trong mẫu, ngoại trừ cú pháp lặp lại hữu hạn (ví dụ: a{3,5}khớp giữa 3 và 5 a).

Định nghĩa phạm vi thay vào đó sử dụng mã hóa ASCII / Unicode của các ký tự để xác định phạm vi. Ký tự 0được mã hóa trong ASCII dưới dạng số thập phân 48; 9là 57. Do đó, định nghĩa ký tự [0-9]bao gồm tất cả các ký tự có giá trị từ số thập phân 48 đến 57 trong bảng mã. Thay vào đó một cách hợp lý, theo thiết kế đó là những ký tự 0, 1, ..., 9.

Xem thêm


Một ví dụ khác: A đến Z

Chúng ta hãy xem xét một định nghĩa lớp ký tự phổ biến khác [a-zA-Z]

Trong ASCII:

  • A= 65, Z= 90
  • a= 97, z= 122

Điều này có nghĩa rằng:

  • [a-zA-Z][A-Za-z]tương đương
  • Trong hầu hết các hương vị, [a-Z]có thể là một phạm vi ký tự bất hợp pháp
    • bởi vì a(97) là "lớn hơn" hơn Z(90)
  • [A-z] là hợp pháp, nhưng cũng bao gồm sáu ký tự sau:
    • [(91), \(92), ](93), ^(94), _(95), `(96)

Câu hỏi liên quan


Đối với tôi, tôi đã tìm kiếm hàng tháng mà không có tiền tố 0 nếu là một chữ số. Và tôi đã sử dụng cái này ([1-9] | (1 [0-2])) và nó hoạt động.
bunjeeb

2
Điều quan trọng cần lưu ý: Nếu bạn thấy trang này muốn giải pháp cho dải số chỉ có các chữ số đơn lẻ trước khi đến hàng chục, 0[1-9]|1[0-2]sẽ không hoạt động. Thay đổi nó sang bước tiếp theo logic [1-9]|1[0-2]không hoạt động hoặc vì những lý do dễ hiểu (Nó phù hợp với 1chỉ trong 10, 1112). Phải sử dụng \b(?:[0-9]|1[0-1])\bđể ngăn chặn điều đó. \bđảm bảo regex khớp với ranh giới từ (hoặc trong trường hợp này là số) ( ^& $không); dấu ngoặc làm cho hoặc ( |) xem xét mặt khác của nó; và cuối cùng ?:là không tạo một submatch với việc sử dụng các dấu ngoặc.
user66001 13/04/17

@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )Bạn có thể vui lòng cho tôi biết tại sao JS regex này khớp trên 17 không?
edam

@edam - polygenelubricants thể, và như vậy có thể tôi, nhưng sau đó chúng tôi muốn được trả lời một questi ... chờ đợi ... Đây là một câu hỏi bạn đang yêu cầu trong một bình luận ? Có rulez trên trang web này;) Đặt câu hỏi nếu bạn có câu hỏi mới. Nhận xét chỉ để phê bình và yêu cầu làm rõ, và để phản hồi những điều đó.
robinCTS

1
@edam Ồ, tôi hiểu rồi. Bạn đã hỏi lại nó như một câu hỏi một giờ sau đó. Thật tuyệt! Tuy nhiên, có lẽ nên xóa bình luận của bạn ở đây.
robinCTS

24

Một lớp ký tự trong biểu thức chính quy, được biểu thị bằng [...]cú pháp, chỉ định các quy tắc để khớp với một ký tự duy nhất trong đầu vào. Như vậy, mọi thứ bạn viết giữa các dấu ngoặc sẽ chỉ định cách khớp với một ký tự .

[01-12]Do đó , mẫu của bạn được chia nhỏ như sau:

  • 0 - khớp với chữ số duy nhất 0
  • hoặc 1-1, khớp với một chữ số duy nhất trong phạm vi từ 1 đến 1
  • hoặc, 2, khớp với một chữ số 2

Vì vậy, về cơ bản tất cả những gì bạn đang khớp là 0, 1 hoặc 2.

Để thực hiện đối sánh bạn muốn, đối sánh hai chữ số, từ 01-12 dưới dạng số, bạn cần nghĩ xem chúng sẽ trông như thế nào dưới dạng văn bản.

Bạn có:

  • 01-09 (tức là chữ số đầu tiên là 0, chữ số thứ hai là 1-9)
  • 10-12 (tức là chữ số đầu tiên là 1, chữ số thứ hai là 0-2)

Sau đó, bạn sẽ phải viết một biểu thức chính quy cho điều đó, có thể giống như sau:

  +-- a 0 followed by 1-9
  |
  |      +-- a 1 followed by 0-2
  |      |
<-+--> <-+-->
0[1-9]|1[0-2]
      ^
      |
      +-- vertical bar, this roughly means "OR" in this context

Lưu ý rằng cố gắng kết hợp chúng để có được một biểu thức ngắn hơn sẽ không thành công, bằng cách đưa ra các kết quả phù hợp dương sai cho đầu vào không hợp lệ.

Ví dụ: [0-1][0-9]về cơ bản , mẫu sẽ khớp với các số 00-19, nhiều hơn một chút so với những gì bạn muốn.

Tôi đã cố gắng tìm một nguồn xác định để biết thêm thông tin về các lớp nhân vật, nhưng bây giờ tất cả những gì tôi có thể cung cấp cho bạn là Truy vấn Google dành cho Lớp nhân vật Regex này . Hy vọng rằng bạn sẽ có thể tìm thêm một số thông tin ở đó để giúp bạn.


9

Điều này cũng hoạt động:

^([1-9]|[0-1][0-2])$

[1-9] khớp các chữ số đơn từ 1 đến 9

[0-1][0-2] khớp các chữ số đôi từ 10 đến 12

Có một số ví dụ điển hình ở đây


2
Nói chính xác, [0-1][0-2]cũng trùng khớp 00. Điều đó nói rằng, +1 cho liên kết (mà tôi đã sử dụng trong câu trả lời của mình).
polygenelubricants

2
[0-1][0-2]phải được giải thích một cách cẩn thận, vì nó cho phép chuỗi thích 00, 0102, nhưng nó không thừa nhận 03lên đến 09, thừa nhận cuối cùng 10,1112. Một regex phù hợp cho điều đó là [1-9]|1[0-2], hoặc thậm chí 0*([1-9]|1[0-2])(điều này cuối cùng cho phép bất kỳ số 0 ở đầu nào).
Luis Colorado

1

Các []s trong một regex biểu thị một lớp ký tự . Nếu không có phạm vi nào được chỉ định, nó ngầm định hoặc s tất cả các ký tự bên trong nó cùng nhau. Vì vậy, [abcde]giống như (a|b|c|d|e), ngoại trừ việc nó không nắm bắt bất cứ điều gì; nó sẽ khớp với bất kỳ một trong số a,b , c, d, hoặc e. Tất cả một phạm vi chỉ ra là một tập hợp các ký tự ; [ac-eg]cho biết "khớp với bất akỳ ký tự nào trong số :; bất kỳ ký tự nào giữa ce; hoặc g". Do đó, kết quả khớp của bạn cho biết "khớp với bất 0kỳ ký tự nào trong số :; bất kỳ ký tự nào giữa 11( tức là chỉ 1); hoặc 2.

Mục tiêu của bạn rõ ràng là chỉ định một dải số: bất kỳ số nào ở giữa 0112được viết bằng hai chữ số. Trong trường hợp cụ thể này, bạn có thể so khớp nó với 0[1-9]|1[0-2]: 0theo sau bởi bất kỳ chữ số nào giữa 19, hoặc 1theo sau bởi bất kỳ chữ số nào giữa 02. Nói chung, bạn có thể chuyển đổi bất kỳ dải số nào thành một regex hợp lệ theo cách tương tự. Tuy nhiên, có thể có một lựa chọn tốt hơn các biểu thức chính quy, hoặc một hàm hoặc mô-đun hiện có có thể tạo regex cho bạn. Nó phụ thuộc vào ngôn ngữ của bạn.


0

Như polygenelubricants nói rằng của bạn sẽ tìm kiếm 0 | 1-1 | 2 hơn là những gì bạn muốn, do thực tế là các lớp ký tự (những thứ trong []) khớp với ký tự chứ không phải chuỗi.


3
0|1-1|2- ký hiệu này rất dễ gây hiểu nhầm. Một cái gì đó giống như 0|1|2sẽ chính xác hơn.
polygenelubricants

0

Dùng cái này:

0?[1-9]|1[012]
  • 07: hợp lệ
  • 7: hợp lệ
  • 0: không khớp
  • 00: không khớp
  • 13: không khớp
  • 21: không khớp

Để kiểm tra một mẫu vào tháng 07/2018, hãy sử dụng cái này:

/^(0?[1-9]|1[012])\/([2-9][0-9]{3})$/

(Phạm vi ngày từ 01/2000 đến 12/9999)


Tôi đã cố gắng tìm ra cách thực hiện điều này nhưng để điều kiện thứ ba chỉ là số 0 vượt qua.
mkaatman
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.