ความแตกต่างระหว่าง re.search และ re.match คืออะไร?


526

อะไรคือความแตกต่างระหว่างsearch()และmatch()ฟังก์ชั่นในโมดูลPythonre ?

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

คำตอบ:


508

re.matchถูกยึดที่จุดเริ่มต้นของสตริง นั่นไม่เกี่ยวข้องกับการขึ้นบรรทัดใหม่ดังนั้นจึงไม่เหมือนกับการใช้^ในรูปแบบ

ในฐานะที่เป็นเอกสาร re.matchพูดว่า:

หากอักขระศูนย์หรือมากกว่าที่ จุดเริ่มต้นของสตริงตรงกับรูปแบบนิพจน์ทั่วไปให้ส่งคืนMatchObjectอินสแตนซ์ที่เกี่ยวข้อง ส่งคืนNoneถ้าสตริงไม่ตรงกับรูปแบบ; โปรดทราบว่านี่จะแตกต่างจากการแข่งขันที่มีความยาวเป็นศูนย์

หมายเหตุ: หากคุณต้องการค้นหาคู่ที่ใดก็ได้ในสตริงให้ใช้search() แทน

re.searchค้นหาสตริงทั้งหมดตามที่เอกสารระบุว่า :

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

matchดังนั้นหากคุณต้องการเพื่อให้ตรงกับที่จุดเริ่มต้นของสตริงหรือเพื่อให้ตรงกับการใช้งานสตริงทั้งหมด มันเร็วกว่า searchมิฉะนั้นใช้

เอกสารมีส่วนเฉพาะสำหรับmatchvs.searchซึ่งครอบคลุมหลายสตริง:

Python เสนอการดำเนินการดั้งเดิมสองแบบที่แตกต่างกันตามนิพจน์ทั่วไป: matchตรวจสอบการจับคู่ เฉพาะตอนต้นของสตริงขณะที่searchตรวจสอบการจับคู่ ที่ใดก็ได้ในสตริง (นี่คือสิ่งที่ Perl ทำตามค่าเริ่มต้น)

โปรดทราบว่าmatchอาจแตกต่างจากsearch แม้เมื่อใช้นิพจน์ทั่วไปที่ขึ้นต้นด้วย'^': '^'จับคู่เฉพาะที่จุดเริ่มต้นของสตริงหรือใน MULTILINEโหมดทันทีหลังจากขึ้นบรรทัดใหม่ การmatchดำเนินการ“” ประสบความสำเร็จเฉพาะในกรณีที่รูปแบบการจับคู่ที่จุดเริ่มต้นของสตริง โดยไม่คำนึงถึงโหมดหรือที่ตำแหน่งเริ่มต้นที่กำหนดโดยpos อาร์กิวเมนต์ตัวเลือกโดยไม่คำนึงถึงว่าขึ้นบรรทัดใหม่นำหน้ามัน

ตอนนี้พูดคุยพอ ได้เวลาดูตัวอย่างโค้ดแล้ว

# example code:
string_with_newlines = """something
someotherthing"""

import re

print re.match('some', string_with_newlines) # matches
print re.match('someother', 
               string_with_newlines) # won't match
print re.match('^someother', string_with_newlines, 
               re.MULTILINE) # also won't match
print re.search('someother', 
                string_with_newlines) # finds something
print re.search('^someother', string_with_newlines, 
                re.MULTILINE) # also finds something

m = re.compile('thing$', re.MULTILINE)

print m.match(string_with_newlines) # no match
print m.match(string_with_newlines, pos=4) # matches
print m.search(string_with_newlines, 
               re.MULTILINE) # also matches

สิ่งที่เกี่ยวกับสตริงที่มีการขึ้นบรรทัดใหม่
Daryl Spitzer

26
ทำไมทุกคนถึงใช้ข้อ จำกัดmatchมากกว่าทั่วไปมากกว่าsearch? สำหรับความเร็วหรือไม่
Alby

13
@ การจับคู่นั้นเร็วกว่าการค้นหาดังนั้นแทนที่จะใช้ regex.search ("คำว่า") คุณสามารถทำ regex.match ((. *?) คำ (. *?)) และรับประสิทธิภาพการทำงานมากมายหากคุณทำงานด้วย ตัวอย่างนับล้าน
ivan_bilan

20
นั่นมันโง่นะ เรียกมันว่าทำไมmatch? เป็นกลอุบายที่ฉลาดในการเพาะ API ด้วยชื่อที่ไม่ได้ใช้งานง่ายเพื่อบังคับให้ฉันอ่านเอกสารหรือไม่? ฉันยังคงไม่ทำ! กบฎ!
Sammaron

1
@ivan_bilan matchดูเล็กน้อยfasterกว่าการค้นหาเมื่อใช้นิพจน์ทั่วไปที่เหมือนกัน แต่ตัวอย่างของคุณดูเหมือนผิดไปจากการทดสอบประสิทธิภาพ: stackoverflow.com/questions/180986/…
baptx

101

search ⇒ค้นหาบางสิ่งบางอย่างในสตริงและส่งคืนออบเจ็กต์ที่ตรงกัน

match⇒ค้นหาบางอย่างที่จุดเริ่มต้นของสตริงและส่งคืนวัตถุที่ตรงกัน


49

re.search ค้นหา es สำหรับรูปแบบทั่วทั้งสตริงในขณะที่re.matchไม่ได้ค้นหารูปแบบ; หากไม่เป็นเช่นนั้นจะไม่มีตัวเลือกอื่นนอกจากจับคู่เมื่อเริ่มต้นของสตริง


5
ทำไมการแข่งขันเริ่มต้น แต่ไม่ใช่จนถึงตอนท้ายของสตริง ( fullmatchใน phyton 3.4)
Smit Johnth

49

การจับคู่นั้นเร็วกว่าการค้นหาดังนั้นแทนที่จะทำ regex.search ("คำว่า") คุณสามารถทำ regex.match ((. *?) คำ (. *?)) และรับประสิทธิภาพการทำงานมากมายหากคุณทำงานกับคนนับล้าน ตัวอย่าง

ความคิดเห็นจาก @ivan_bilan ภายใต้คำตอบที่ได้รับการยอมรับข้างต้นทำให้ฉันคิดว่าแฮ็คนั้นเร่งอะไรขึ้นมาบ้างดังนั้นลองมาดูกันว่าคุณจะได้รับประสิทธิภาพการทำงานกี่ตัน

ฉันเตรียมชุดทดสอบต่อไปนี้:

import random
import re
import string
import time

LENGTH = 10
LIST_SIZE = 1000000

def generate_word():
    word = [random.choice(string.ascii_lowercase) for _ in range(LENGTH)]
    word = ''.join(word)
    return word

wordlist = [generate_word() for _ in range(LIST_SIZE)]

start = time.time()
[re.search('python', word) for word in wordlist]
print('search:', time.time() - start)

start = time.time()
[re.match('(.*?)python(.*?)', word) for word in wordlist]
print('match:', time.time() - start)

ฉันทำการวัด 10 ครั้ง (1M, 2M, ... , 10M คำ) ซึ่งให้พล็อตต่อไปนี้แก่ฉัน:

การจับคู่กับพล็อตบรรทัดการทดสอบ regex speed search

เส้นที่เกิดขึ้นนั้นน่าแปลกใจ (ที่จริงแล้วไม่น่าประหลาดใจ) ตรง และsearchฟังก์ชั่นนี้จะเร็วขึ้น (เล็กน้อย)เนื่องจากการรวมรูปแบบเฉพาะนี้ คุณธรรมของการทดสอบนี้: หลีกเลี่ยงการเพิ่มรหัสของคุณมากเกินไป


12
+1 สำหรับการตรวจสอบสมมติฐานที่อยู่เบื้องหลังข้อความสั่งจริง ๆ แล้วต้องใช้ราคาที่เหมาะสม - ขอบคุณ
Robert Dodier

อันที่จริงความคิดเห็นของ @ivan_bilan นั้นผิด แต่matchฟังก์ชั่นนั้นยังเร็วกว่าsearchฟังก์ชั่นถ้าคุณเปรียบเทียบนิพจน์ปกติแบบเดียวกัน คุณสามารถตรวจสอบในสคริปต์ของคุณโดยเปรียบเทียบre.search('^python', word)กับre.match('python', word)(หรือre.match('^python', word)เหมือนกัน แต่ง่ายต่อการเข้าใจหากคุณไม่ได้อ่านเอกสารและดูเหมือนจะไม่ส่งผลกระทบต่อประสิทธิภาพ)
baptx

@ baptx ฉันไม่เห็นด้วยกับคำสั่งที่matchฟังก์ชั่นโดยทั่วไปเร็วขึ้น matchเป็นเร็วขึ้นเมื่อคุณต้องการค้นหาที่จุดเริ่มต้นของสตริงที่searchเป็นเร็วขึ้นเมื่อคุณต้องการค้นหาตลอดทั้งสตริง ซึ่งสอดคล้องกับสามัญสำนึก นั่นเป็นเหตุผลที่ @ivan_bilan ผิด - เขาเคยmatchค้นหาตลอดทั้งสาย นั่นเป็นเหตุผลว่าทำไมคุณถึงถูกต้อง - คุณเคยmatchค้นหาที่จุดเริ่มต้นของสตริง หากคุณไม่เห็นด้วยกับฉันลองค้นหา regex matchที่เร็วกว่าre.search('python', word)และทำงานเดียวกัน
Jeyekomon

@baptx ยังเป็นเชิงอรรถที่re.match('python') เป็นre.match('^python')เล็กน้อยเร็วกว่า มันจะต้องมี
Jeyekomon

@ Jeyekomon ใช่นั่นคือสิ่งที่ฉันหมายถึงmatchฟังก์ชั่นจะเร็วขึ้นเล็กน้อยถ้าคุณต้องการค้นหาที่จุดเริ่มต้นของสตริง (เปรียบเทียบกับการใช้searchฟังก์ชันเพื่อค้นหาคำที่จุดเริ่มต้นของสตริงด้วยre.search('^python', word)) แต่ฉันพบว่ามันแปลก ๆ ถ้าคุณบอกให้searchฟังก์ชั่นค้นหาที่จุดเริ่มต้นของสตริงมันควรจะเร็วเท่ากับmatchฟังก์ชั่น
baptx

31

คุณสามารถอ้างอิงตัวอย่างด้านล่างเพื่อทำความเข้าใจเกี่ยวกับการทำงานre.matchและ re.search

a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)

re.matchจะกลับมาnoneแต่จะกลับมาre.searchabc


3
ต้องการเพิ่มการค้นหานั้นจะส่งคืนวัตถุ _sre.SRE_Match (หรือไม่มีหากไม่พบ) ในการรับ 'abc' คุณต้องโทร t.group ()
SanD

30

ความแตกต่างคือre.match()ทำให้เข้าใจผิดทุกคนที่คุ้นเคยกับการจับคู่การแสดงออกปกติPerl , grepหรือsedและre.search()ไม่ :-)

อย่างมีสติมากขึ้นดังที่ John D. Cook พูดว่าre.match()"ประพฤติเหมือนทุกรูปแบบมี ^ prepended" ในคำอื่น ๆเท่ากับre.match('pattern') re.search('^pattern')ดังนั้นจึงยึดด้านซ้ายของรูปแบบ แต่ก็ยังไม่ได้ยึดด้านขวาของรูปแบบ:$ที่ยังคงต้องยุติ

ฉันคิดว่าน่าre.match()จะถูกปฏิเสธ ฉันอยากรู้เหตุผลที่ควรเก็บไว้


4
"ทำงานราวกับว่าทุกรูปแบบมี ^ prepended" เป็นจริงเฉพาะในกรณีที่คุณไม่ได้ใช้ตัวเลือกหลายบรรทัด คำสั่งที่ถูกต้องคือ "... มี \ A prepended"
JoelFan

14

ความพยายามในการ re.match เพื่อให้ตรงกับรูปแบบที่จุดเริ่มต้นของสตริง re.search พยายามจับคู่รูปแบบตลอดทั้งสตริงจนกว่าจะพบการจับคู่


3

สั้นกว่ามาก:

  • search สแกนผ่านสายอักขระทั้งหมด

  • match สแกนเฉพาะจุดเริ่มต้นของสตริง

ต่อไปนี้ Ex พูดว่า:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.