Python regex tìm tất cả các kết quả trùng khớp?


98

Tôi đang cố gắng tìm mọi chuỗi số có 10 chữ số trong một chuỗi số lớn hơn bằng cách sử dụng re trong Python 2.6.

Tôi có thể dễ dàng nắm bắt các trận đấu không trùng lặp, nhưng tôi muốn mọi trận đấu đều theo dãy số. Ví dụ.

trong "123456789123456789"

Tôi sẽ nhận được danh sách sau:

[1234567891,2345678912,3456789123,4567891234,5678912345,6789123456,7891234567,8912345678,9123456789]

Tôi đã tìm thấy các tham chiếu đến "lookahead", nhưng các ví dụ mà tôi đã thấy chỉ hiển thị các cặp số chứ không phải các nhóm lớn hơn và tôi không thể chuyển đổi chúng ngoài hai chữ số.


6
Các giải pháp đã trình bày sẽ không hoạt động khi các kết quả trùng khớp bắt đầu tại cùng một điểm, ví dụ: so khớp "a | ab | abc" với "abcd" sẽ chỉ trả về một kết quả. Có giải pháp nào cho điều đó không liên quan đến việc gọi match () nhiều lần, theo dõi ranh giới 'kết thúc' theo cách thủ công không?
Vítor De Araújo

@ VítorDeAraújo: các regexes chồng chéo như (a|ab|abc)thường có thể được viết lại thành các regex không chồng chéo với các nhóm capture lồng nhau, ví dụ: (a(b(c)?)?)?nơi chúng tôi bỏ qua tất cả trừ nhóm chụp ngoài cùng (tức là ngoài cùng bên trái) khi giải nén một trận đấu; phải thừa nhận rằng điều này hơi đau và ít rõ ràng hơn. Đây cũng sẽ là một regex hiệu quả hơn để phù hợp.
smci

Câu trả lời:


175

Sử dụng một nhóm chụp bên trong một cái nhìn trước. Phần nhìn trước ghi lại văn bản mà bạn quan tâm, nhưng kết hợp thực tế về mặt kỹ thuật là chuỗi con có độ rộng bằng 0 trước phần nhìn trước, do đó, các kết hợp về mặt kỹ thuật là không chồng chéo:

import re 
s = "123456789123456789"
matches = re.finditer(r'(?=(\d{10}))',s)
results = [int(match.group(1)) for match in matches]
# results: 
# [1234567891,
#  2345678912,
#  3456789123,
#  4567891234,
#  5678912345,
#  6789123456,
#  7891234567,
#  8912345678,
#  9123456789]

2
Câu trả lời của tôi nhanh hơn câu này ít nhất 2 lần. Nhưng giải pháp này là phức tạp, tôi ủng hộ nó.
eyquem

16
Giải thích = thay vì tìm kiếm mẫu (10 chữ số), nó tìm kiếm bất kỳ thứ gì THEO mẫu. Vì vậy, nó tìm vị trí 0 của chuỗi, vị trí 1 của chuỗi, v.v. Sau đó, nó lấy nhóm (1) - mẫu phù hợp và tạo danh sách các mẫu đó. Rất tuyệt.
Tal Weiss

Tôi không biết bạn có thể sử dụng các nhóm phù hợp bên trong các trang tìm kiếm, những nhóm này thường không được đưa vào một trận đấu (và các nhóm con đã khớp thực sự không xuất hiện khớp hoàn toàn). Vì kỹ thuật này dường như vẫn hoạt động trong Python 3.4, tôi đoán nó được coi là một tính năng hơn là một lỗi.
JAB

10
Tôi đã tham gia StackOverflow, trả lời các câu hỏi và nâng cao danh tiếng của mình để tôi có thể ủng hộ câu trả lời này. Tôi đang bị mắc kẹt với Python 2.4 vì vậy tôi không thể sử dụng các hàm regex nâng cao hơn của Python 3 và đây chỉ là một loại thủ thuật kỳ lạ mà tôi đang tìm kiếm.
TheSoundDefense,

2
Bạn có thể thêm giải thích thêm cho mã. Đó không phải là cách tốt nhất theo Stack Overflow, chỉ có mã trong một câu trả lời. Nó chắc chắn sẽ giúp ích cho mọi người.
Akshay Hazari

77

Bạn cũng có thể thử sử dụng mô-đun của bên thứ baregex (không phải re), mô-đun này hỗ trợ các kết quả trùng khớp.

>>> import regex as re
>>> s = "123456789123456789"
>>> matches = re.findall(r'\d{10}', s, overlapped=True)
>>> for match in matches: print match
...
1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789

17

Tôi thích regexes, nhưng chúng không cần thiết ở đây.

Đơn giản

s =  "123456789123456789"

n = 10
li = [ s[i:i+n] for i in xrange(len(s)-n+1) ]
print '\n'.join(li)

kết quả

1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789

10
Regexes chỉ là không cần thiết ở đây vì bạn đang áp dụng kiến ​​thức đặc biệt "trong một chuỗi số lớn hơn", vì vậy bạn đã biết mọi vị trí 0 <= i < len(s)-n+1được đảm bảo là điểm bắt đầu của một trận đấu 10 chữ số. Ngoài ra, tôi nghĩ rằng mã của bạn có thể được tăng tốc, sẽ rất thú vị khi viết mã để tăng tốc độ.
smci
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.