Regex cho chuỗi không kết thúc với hậu tố đã cho


187

Tôi đã không thể tìm thấy một regex thích hợp để khớp với bất kỳ chuỗi nào không kết thúc với một số điều kiện. Ví dụ: tôi không muốn khớp bất cứ thứ gì kết thúc bằng một a.

Trận đấu này

b
ab
1

Điều này không phù hợp

a
ba

Tôi biết regex nên kết thúc bằng $để đánh dấu kết thúc, mặc dù tôi không biết cái gì nên có trước nó.

Chỉnh sửa : Câu hỏi ban đầu dường như không phải là một ví dụ hợp pháp cho trường hợp của tôi. Vậy: làm thế nào để xử lý nhiều hơn một nhân vật? Nói gì không kết thúc ab?

Tôi đã có thể sửa lỗi này, sử dụng chuỗi này :

.*(?:(?!ab).).$

Mặc dù nhược điểm của điều này là, nó không khớp với một chuỗi gồm một ký tự.


5
Đây không phải là một bản sao của câu hỏi được liên kết - chỉ khớp với kết thúc yêu cầu một cú pháp khác với so sánh ở bất kỳ đâu trong chuỗi. Chỉ cần nhìn vào câu trả lời hàng đầu ở đây.
jaustin

Tôi đồng ý, đây không phải là một bản sao của câu hỏi được liên kết. Tôi tự hỏi làm thế nào chúng ta có thể loại bỏ các "dấu hiệu" ở trên?
Alan Cabrera

Không có liên kết như vậy mà tôi có thể nhìn thấy.
Alan Cabrera

Câu trả lời:


249

Bạn không cung cấp cho chúng tôi ngôn ngữ, nhưng nếu hỗ trợ hương vị regex của bạn nhìn phía sau khẳng định , đây là thứ bạn cần:

.*(?<!a)$

(?<!a)là một xác nhận giao diện phủ định đảm bảo rằng trước khi kết thúc chuỗi (hoặc hàng có msửa đổi), không có ký tự "a".

Xem nó ở đây trên Regexr

Bạn cũng có thể dễ dàng mở rộng điều này với các ký tự khác, vì việc kiểm tra chuỗi này và không phải là một lớp ký tự.

.*(?<!ab)$

Điều này sẽ phù hợp với bất cứ điều gì không kết thúc bằng "ab", xem nó trên Regexr


1
Tôi không biết RegexPAL, nhưng regexes khác nhau ở tất cả các ngôn ngữ và xác nhận giao diện là một tính năng nâng cao không được hỗ trợ bởi tất cả.
phù nề

7
regrecal là một trình kiểm tra regex dựa trên javascript và javascript không hỗ trợ các xác nhận tìm kiếm đáng buồn
HamZa

Lookbehinds không được hỗ trợ trên regexr (javascript)
Rabbi tàng hình

1
Thiếu cái nhìn trong JS làm tôi khóc. Nếu bạn đang làm phía máy chủ mặc dù bạn có thể sử dụng mô-đun PCRE trên NPM hoặc tương tự để sử dụng chúng trực tiếp (đó là một tập hợp các ràng buộc nên tôi không nghĩ bạn có thể sử dụng nó ở mặt trước)
Eirik Birkeland 18/03

Nhiều loại xác nhận lookahead / lookbehind: stackoverflow.com/q/2973436/12484
Jon Schneider

76

Sử dụng ký hiệu không ( ^):

.*[^a]$

Nếu bạn đặt ^biểu tượng ở đầu ngoặc, nó có nghĩa là "mọi thứ trừ những thứ trong ngoặc". $chỉ đơn giản là một mỏ neo đến cuối cùng.

Đối với nhiều ký tự , chỉ cần đặt tất cả chúng vào bộ ký tự của riêng chúng:

.*[^a][^b]$

1
+1, với lời cảnh báo rằng điều này không khớp với chuỗi trống (có thể có hoặc không như dự định), vì vậy ý ​​nghĩa là "bất kỳ ký tự nào không có trong ngoặc".
Fred Foo

3
@ 0A0D: một chuỗi chứa khoảng trắng không phải là một chuỗi rỗng.
Fred Foo

7
@ 0A0D Trên thực tế, đó không phải là tranh luận, đó là sự thật
tckmn

8
@Doorknob: không phù hợp aehoặc cb.
Fred Foo

1
Không, điều này cũng không cho phép "acb".
Menno

48

Để tìm kiếm các tệp không kết thúc bằng ".tmp", chúng tôi sử dụng regex sau:

^(?!.*[.]tmp$).*$

Đã thử nghiệm với Regex Tester cho kết quả như sau:

nhập mô tả hình ảnh ở đây


1
Điều này thật thú vị, bất kỳ ý tưởng tại sao điều này hoạt động và tại sao ^.*(?![.]tmp$)không?
Łukasz Zaroda

4
Sớm .*không đã phù hợp với toàn bộ chuỗi, do đó loại trừ còn lại không hoạt động nữa.
FiveO

Đối với mục đích của tôi, điều này đã làm việc và các câu trả lời khác đã không. Cảm ơn!
David Moritz

8
.*[^a]$

regex ở trên sẽ khớp với các chuỗi không kết thúc bằng a.


Tôi đã mở rộng câu hỏi của mình vì ví dụ ban đầu dường như không hoàn toàn khớp với trường hợp của tôi. Bạn có thể giải quyết nó?
Menno

5

Thử cái này

/.*[^a]$/

Các []biểu thị một lớp nhân vật, và ^sẽ đảo ngược lớp nhân vật để phù hợp với tất cả mọi thứ nhưng một a.


1

Câu hỏi đã cũ nhưng tôi không thể tìm thấy giải pháp nào tốt hơn tôi đăng ở đây. Tìm tất cả các ổ USB nhưng không liệt kê các phân vùng , do đó loại bỏ "phần [0-9]" khỏi kết quả. Tôi đã kết thúc hai grep, cuối cùng phủ nhận kết quả:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

Kết quả này trên hệ thống của tôi:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Nếu tôi chỉ muốn các phân vùng tôi có thể làm:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

Nơi tôi nhận được:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

Và khi tôi làm:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Tôi có:

/dev/sdb

1

Câu trả lời được chấp nhận là tốt nếu bạn có thể sử dụng nhìn. Tuy nhiên, cũng có một cách tiếp cận khác để giải quyết vấn đề này.

Nếu chúng ta nhìn vào regex được đề xuất rộng rãi cho câu hỏi này:

.*[^a]$

Chúng tôi sẽ thấy rằng nó gần như hoạt động. Nó không chấp nhận một chuỗi rỗng, có thể hơi bất tiện. Tuy nhiên, đây chỉ là một vấn đề nhỏ khi xử lý chỉ một nhân vật. Tuy nhiên, nếu chúng tôi muốn loại trừ toàn bộ chuỗi, ví dụ: "abc", thì:

.*[^a][^b][^c]$

sẽ không làm. Nó sẽ không chấp nhận ac, ví dụ.

Có một giải pháp dễ dàng cho vấn đề này mặc dù. Chúng ta có thể nói một cách đơn giản:

.{,2}$|.*[^a][^b][^c]$

hoặc phiên bản tổng quát hơn:

.{,n-1}$|.*[^firstchar][^secondchar]$ trong đó n là chiều dài của chuỗi bạn muốn cấm (đối với abcnó là 3), và firstchar, secondchar... là đầu tiên, nhân vật thứ hai ... thứ n của chuỗi của bạn (ví abcnó sẽ là a, sau đó b, sau đó c).

Điều này xuất phát từ một quan sát đơn giản rằng một chuỗi ngắn hơn văn bản mà chúng tôi sẽ không cấm không thể chứa văn bản này theo định nghĩa. Vì vậy, chúng tôi có thể chấp nhận bất cứ điều gì ngắn hơn ("ab" không phải là "abc") hoặc bất cứ điều gì đủ dài để chúng tôi chấp nhận nhưng không có kết thúc.

Đây là một ví dụ về tìm kiếm sẽ xóa tất cả các tệp không phải là .jpg:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$không khớpccc
psalaets

0

Bất cứ điều gì phù hợp với một cái gì đó kết thúc bằng một --- .*a$Vì vậy, khi bạn kết hợp regex, phủ nhận tình trạng này hay cách khác bạn cũng có thể làm .*[^a]$nơi [^a]phương tiện bất cứ điều gì đó lànot a


0

Nếu bạn đang sử dụng grephoặc sedcú pháp sẽ có một chút khác biệt. Lưu ý rằng [^a][^b]phương pháp tuần tự không hoạt động ở đây:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW, tôi đang tìm thấy kết quả tương tự trong Regex101 , mà tôi nghĩ là cú pháp JavaScript.

Xấu: https://regex101.com/r/MJGAmX/2
Tốt: https://regex101.com/r/LzrIBu/2

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.