Python regex พบการจับคู่ที่ทับซ้อนกันทั้งหมดหรือไม่


101

ฉันกำลังพยายามค้นหาชุดตัวเลขทุกๆ 10 หลักภายในชุดตัวเลขขนาดใหญ่โดยใช้ re ใน Python 2.6

ฉันไม่สามารถคว้าการแข่งขันที่ไม่ทับซ้อนกันได้อย่างง่ายดาย แต่ฉันต้องการทุกนัดในซีรีย์ตัวเลข เช่น.

ใน "123456789123456789"

ฉันควรได้รับรายชื่อต่อไปนี้:

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

ฉันพบการอ้างอิงถึง "lookahead" แต่ตัวอย่างที่ฉันเห็นแสดงเฉพาะคู่ของตัวเลขแทนที่จะเป็นการจัดกลุ่มขนาดใหญ่และฉันไม่สามารถแปลงค่าได้เกินสองหลัก


6
โซลูชันที่นำเสนอจะไม่ทำงานเมื่อการจับคู่ที่ทับซ้อนกันเริ่มต้นที่จุดเดียวกันเช่นการจับคู่ "a | ab | abc" กับ "abcd" จะให้ผลลัพธ์เพียงหนึ่งรายการ มีวิธีแก้ปัญหาที่ไม่เกี่ยวข้องกับการเรียกจับคู่ () หลายครั้งติดตามขอบเขต 'สิ้นสุด' ด้วยตนเองหรือไม่
Vítor De Araújo

@ VítorDeAraújo: regexes ที่ทับซ้อนกันเหมือน(a|ab|abc)โดยทั่วไปสามารถเขียนใหม่เป็นรายการที่ไม่ทับซ้อนกันโดยมีกลุ่มการจับภาพซ้อนกันเช่น(a(b(c)?)?)?โดยที่เราจะเพิกเฉยต่อกลุ่มการจับภาพทั้งหมดยกเว้นที่อยู่นอกสุด (เช่นซ้ายสุด) เมื่อคลายการบรรจุการแข่งขัน เป็นที่ยอมรับว่านี่เป็นความเจ็บปวดเล็กน้อยและชัดเจนน้อยลง นี่จะเป็นนิพจน์ทั่วไปที่มีประสิทธิภาพมากขึ้น
smci

คำตอบ:


180

ใช้กลุ่มการจับภาพภายในผู้มองหา ผู้มองหาจะจับข้อความที่คุณสนใจ แต่การจับคู่จริงในทางเทคนิคคือสตริงย่อยที่มีความกว้างเป็นศูนย์ก่อนหน้าการค้นหาดังนั้นการจับคู่จะไม่ทับซ้อนกันในทางเทคนิค:

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
คำตอบของฉันเร็วกว่าข้อนี้อย่างน้อย 2 เท่า แต่วิธีนี้ยุ่งยากฉันโหวตให้
eyquem

16
Explanation = แทนที่จะค้นหารูปแบบ (ตัวเลข 10 หลัก) จะค้นหาสิ่งที่ตามรูปแบบ ดังนั้นจะพบตำแหน่ง 0 ของสตริงตำแหน่ง 1 ของสตริงและอื่น ๆ จากนั้นจะจับกลุ่ม (1) - รูปแบบการจับคู่และสร้างรายการเหล่านั้น เจ๋งมาก
Tal Weiss

10
ฉันเข้าร่วม StackOverflow ตอบคำถามและมีชื่อเสียงมากขึ้นเพื่อที่ฉันจะได้โหวตคำตอบนี้ ตอนนี้ฉันติด Python 2.4 ดังนั้นฉันจึงไม่สามารถใช้ฟังก์ชัน regex ขั้นสูงของ Python 3 ได้และนี่เป็นเพียงกลอุบายแปลก ๆ ที่ฉันกำลังมองหา
TheSoundDefense

2
คุณช่วยเพิ่มคำอธิบายเพิ่มเติมให้กับโค้ดได้ไหม ไม่ใช่วิธีที่ดีที่สุดตาม Stack Overflow เพียงแค่มีรหัสในคำตอบ มันจะช่วยคนได้แน่นอน
Akshay Hazari

1
นี่เป็นประโยชน์จริงๆ ขอบคุณ: D
Sreekiran

80

คุณยังสามารถลองใช้โมดูลของบุคคลที่สามregex (ไม่ใช่re) ซึ่งรองรับการจับคู่ที่ทับซ้อนกัน

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

ฉันได้รับ:TypeError: findall() got an unexpected keyword argument 'overlapped'
Carsten

@Carsten: ก่อนอื่นคุณต้องติดตั้งregexโมดูล:pip install regex
David C

ที่ได้ผลขอบคุณ ฉันคิดว่าจะได้รับข้อผิดพลาดในการนำเข้าหากไม่ได้ติดตั้ง regex
Carsten

17

ฉันชอบ regexes แต่ไม่จำเป็นที่นี่

เพียงแค่

s =  "123456789123456789"

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

ผลลัพธ์

1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789

10
ไม่จำเป็นต้องใช้ Regexes ที่นี่เพราะคุณกำลังใช้ความรู้พิเศษ "ภายในชุดตัวเลขที่ใหญ่กว่า" ดังนั้นคุณจึงรู้อยู่แล้วว่าทุกตำแหน่ง0 <= i < len(s)-n+1จะเป็นจุดเริ่มต้นของการจับคู่ 10 หลัก นอกจากนี้ฉันคิดว่ารหัสของคุณสามารถเร่งความเร็วได้น่าสนใจสำหรับการตีกอล์ฟเพื่อความเร็ว
smci
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.