การหลบหนีสตริง regex ใน Python


229

ฉันต้องการใช้อินพุตจากผู้ใช้เป็นรูปแบบ regex สำหรับการค้นหาข้อความ มันใช้งานได้ แต่ฉันจะจัดการกรณีที่ผู้ใช้ใส่อักขระที่มีความหมายใน regex ได้อย่างไร ตัวอย่างเช่นผู้ใช้ต้องการค้นหา Word (s): เครื่องมือ regex จะใช้(s)เป็นกลุ่ม "(s)"ฉันต้องการที่จะรักษามันเหมือนสตริง ฉันสามารถเรียกใช้replaceในการป้อนข้อมูลของผู้ใช้และแทนที่(ด้วย\(และ)ด้วย\)แต่ปัญหาคือฉันจะต้องเปลี่ยนทุกสัญลักษณ์ regex คุณรู้วิธีที่ดีกว่านี้ไหม?

คำตอบ:


324

ใช้re.escape()ฟังก์ชั่นนี้:

4.2.3 reเนื้อหาโมดูล

หลบหนี (สตริง)

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

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

def simplistic_plural(word, text):
    word_or_plural = re.escape(word) + 's?'
    return re.match(word_or_plural, text)

53

คุณสามารถใช้re.escape () :

re.escape (string) ส่งคืนสตริงที่มีเครื่องหมายแบ็กสแลชที่ไม่ใช่ตัวอักษรและตัวเลขทั้งหมด สิ่งนี้มีประโยชน์หากคุณต้องการจับคู่สตริงตามตัวอักษรที่อาจมีอักขระเมตาปกติในนั้น

>>> import re
>>> re.escape('^a.*$')
'\\^a\\.\\*\\$'

3

น่าเสียดายที่re.escape()ไม่เหมาะสำหรับสตริงการแทนที่:

>>> re.sub('a', re.escape('_'), 'aa')
'\\_\\_'

วิธีการแก้ปัญหาคือการใส่ลงในแลมบ์ดา:

>>> re.sub('a', lambda _: '_', 'aa')
'__'

เพราะค่าส่งคืนของแลมบ์ดาถือว่าre.sub()เป็นสตริงตัวอักษร


3
replอาร์กิวเมนต์re.subเป็นสตริงไม่ regex นั้น การนำre.escapeไปใช้กับมันไม่ได้ทำให้รู้สึกใด ๆ ในสถานที่แรก
tripleee

5
@tripleee นั่นไม่ถูกต้องreplอาร์กิวเมนต์ไม่ใช่สตริงธรรมดา แต่จะถูกแยกวิเคราะห์ ยกตัวอย่างเช่นre.sub(r'(.)', r'\1', 'X')จะกลับมาไม่ได้X \1
Flimm

4
นี่คือคำถามที่เกี่ยวข้องสำหรับการหลบหนีการreplโต้แย้ง: stackoverflow.com/q/49943270/247696
Flimm

3
เปลี่ยนเป็นเวอร์ชั่น 3.3: ตัวอักษร '_' จะไม่หนีอีกต่อไป เปลี่ยนเป็นเวอร์ชั่น 3.7: มีเพียงอักขระที่สามารถมีความหมายพิเศษในการแสดงออกปกติเท่านั้น (ทำไมมันใช้เวลานานมาก)
Cees Timmerman

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.