2016-02-25 14 views
5

Tôi đang sử dụng python 2.6 và cố gắng tìm một loạt các ký tự lặp lại trong chuỗi, giả sử một loạt các số n, ví dụ: nnnnnnnABCnnnnnnnnnDEF. Ở bất kỳ nơi nào của chuỗi, số lượng của n có thể thay đổi.Regex, tìm mẫu chỉ ở giữa chuỗi

Nếu tôi xây dựng một regex như thế này:

re.findall(r'^(((?i)n)\2{2,})', s),

Tôi có thể tìm lần xuất hiện của case-insensitive n 's duy nhất trong đầu của chuỗi, mà là tốt. Nếu tôi làm điều đó như thế này:

re.findall(r'(((?i)n)\2{2,}$)', s),

tôi có thể phát hiện những người duy nhất ở cuối dãy. Nhưng những gì về chỉ ở giữa? Lúc đầu, tôi đã nghĩ đến việc sử dụng re.findall(r'(((?i)n)\2{2,})', s) và hai regex trước đây (-ices?) Để kiểm tra độ dài của danh sách trả về và sự hiện diện của n ở đầu hoặc cuối chuỗi và thực hiện các phép kiểm tra lô-gic , nhưng nó trở thành một sự lộn xộn nếu người khác rất nhanh chóng.

Sau đó, tôi đã cố gắng re.findall(r'(?!^)(((?i)n)\2{2,})', s), mà dường như exlude sự bắt đầu tốt nhưng (?!$) hoặc (?!\z) vào cuối regex chỉ loại trừ cuối cùng n trong ABCnnnn. Cuối cùng, tôi đã cố gắng re.findall(r'(?!^)(((?i)n)\2{2,})\w+', s) mà dường như đôi khi làm việc, nhưng tôi nhận được kết quả lạ ở những người khác. Có vẻ như tôi cần một người nhìn hoặc trông có vẻ ngoài, nhưng tôi không thể quấn đầu quanh họ được.

+0

Thử [ '(<^?!) ((N) \ 2 {2,})' (

+0

có gì sai với '((? I) n) \ 1 {2,}' https://regex101.com/r/oT6vZ1/1? –

+0

hoặc '\ B (?

Trả lời

3

Thay vì sử dụng một regex phức tạp để từ chối kết hợp các ký tự đứng đầu và theo sau n. Là một hơn pythonic phương pháp bạn có thể strip() chuỗi của bạn sau đó tìm thấy tất cả các chuỗi các n s sử dụng re.findall() và một regex đơn giản:

>>> s = "nnnABCnnnnDEFnnnnnGHInnnnnn" 
>>> import re 
>>> 
>>> re.findall(r'n{2,}', s.strip('n'), re.I) 
['nnnn', 'nnnnn'] 

Note: re.IBỏ qua hợp cụ thể cờ mà làm cho regex động cơ khớp với chữ hoa và chữ thường.

+0

'n' là một chuỗi ký tự. Bạn sẽ cần phải 're.sub' họ tôi đoán. –

+0

@ WiktorStribiżew Nó không quan trọng, 'str.strip()' sẽ loại bỏ tất cả các lần xuất hiện đầu và cuối của đối số đã qua. – Kasramvd

+0

@ WiktorStribiżew: có vẻ như 'n' là một nhân vật, xem các bình luận cuối cùng. –

1

LƯU Ý: giải pháp này giả định n có thể là một chuỗi của một số nhân vật. Để có các giải pháp thay thế hiệu quả hơn khi n chỉ là 1 ký tự, hãy xem các câu trả lời khác tại đây.

Bạn có thể sử dụng

(?<!^)(?<!n)((n)\2{2,})(?!$)(?!n) 

Xem regex demo

Các regex sẽ phù hợp lặp đi lặp lại liên tiếp n s (trường hợp bỏ qua có thể đạt được với re.I cờ) mà không phải là ở phần đầu ((?<!^)) hoặc cuối cùng ((?!$)) của chuỗi và không phải trước ((?!n)) hoặc sau ((?<!n)) khác n.

Các (?<!^)(?<!n) là một chuỗi của 2 lookbehinds: (?<!^) nghĩa không tiêu thụ các mô hình tiếp theo nếu bắt đầu bằng sự bắt đầu của chuỗi. Các (?<!n) tiêu cực lookbehind có nghĩa là không tiêu thụ các mô hình tiếp theo nếu trước với n. Các lookaheads tiêu cực (?!$)(?!n) có nghĩa tương tự: (?!$) không khớp nếu sau khi vị trí hiện tại kết thúc chuỗi xảy ra và (?!n) sẽ không khớp nếu n xảy ra sau vị trí hiện tại trong chuỗi (nghĩa là, ngay sau khi kết hợp tất cả liên tiếp n s ..

điều kiện lookaround tất cả phải được đáp ứng, đó là lý do tại sao chúng tôi chỉ nhận được các trận đấu trong cùng Xem IDEONE demo:

import re 
p = re.compile(r'(?<!^)(?<!n)((n)\2{2,})(?!$)(?!n)', re.IGNORECASE) 
s = "nnnnnnnABCnnnnnNnnnnDEFnNn" 
print([x.group() for x in p.finditer(s)]) 
2

Kể từ khi "n" là một nhân vật (và không phải là một subpattern), bạn có thể đơn giản sử dụng:

re.findall(r'(?<=[^n])nn+(?=[^n])(?i)', s) 

hoặc tốt hơn:

re.findall(r'n(?<=[^n]n)n+(?=[^n])(?i)', s) 
Các vấn đề liên quan