regex ที่จะจับคู่ แต่แทนที่เฉพาะบางส่วนของรูปแบบใน python
ตัวอย่างทั้งหมดที่ฉันพบใน stack overflow นั้นซับซ้อนเกินกว่าที่ฉันจะทำวิศวกรรมย้อนกลับได้
ลองพิจารณาตัวอย่างของเล่นนี้
s = "asdfasd a_b dsfd"
ฉันต้องการ s = "asdfasd a'b dsfd"
นั่นคือ: ค้นหาอักขระสองตัวที่คั่นด้วยเครื่องหมายขีดล่างและแทนที่ขีดล่างด้วยเครื่องหมายอะพอสทรอฟี
พยายาม:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
ฉันคิดว่า()
ควรจะแก้ปัญหานี้?
สิ่งที่น่าสับสนยิ่งกว่านั้นก็คือความจริงที่ว่าเราพบตัวละครที่เราต้องการแทนที่สำเร็จแล้ว:
re.findall("[a-z](_)[a-z]",s)
#['_']
ทำไมสิ่งนี้ไม่ถูกแทนที่
ขอบคุณ
คำตอบ
ใช้รูปแบบมองไปข้างหน้าและมองข้างหลัง:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
รูปแบบมองไปข้างหน้า / ข้างหลังมีความกว้างเป็นศูนย์ดังนั้นจึงไม่แทนที่สิ่งใด
UPD:
- ปัญหาคือ
re.sub
จะแทนที่นิพจน์ที่ตรงกันทั้งหมดรวมถึงตัวอักษรก่อนหน้าและตัวอักษรต่อไปนี้ re.findall
ยังคงจับคู่นิพจน์ทั้งหมด แต่ยังมีกลุ่ม (วงเล็บด้านใน) ซึ่งคุณสังเกตเห็น ทั้งแมตช์นิ่งa_b
- นิพจน์ lookahead / lookbehind ตรวจสอบว่าการค้นหาอยู่ข้างหน้า / ตามด้วยรูปแบบ แต่อย่ารวมไว้ในการจับคู่
- อีกทางเลือกหนึ่งคือการสร้างหลายกลุ่มและนำกลุ่มเหล่านั้นมาแทนที่:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
เมื่อใช้re.sub
ต้องจับข้อความที่จะเก็บข้อความที่จะลบไม่ควร
ใช้
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
ดูหลักฐาน
คำอธิบาย
NODE EXPLANATION
--------------------------------------------------------------------------------
( group and capture to \1:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of \1
--------------------------------------------------------------------------------
_ '_'
--------------------------------------------------------------------------------
(?= look ahead to see if there is:
--------------------------------------------------------------------------------
[a-z] any character of: 'a' to 'z'
--------------------------------------------------------------------------------
) end of look-ahead
รหัส Python :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
เอาท์พุต:
asdfasd a'b dsfd
re.sub
จะเข้ามาแทนที่ทุกอย่างที่มันจับคู่
มีวิธีที่กว้างกว่าในการแก้ปัญหาของคุณและคุณไม่จำเป็นต้องแก้ไขนิพจน์ทั่วไปของคุณอีกครั้ง
รหัสด้านล่าง:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0)) if _reg else r
#
re.sub(reg,repl, s)
เอาต์พุต: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
แน่นอนว่าหากกรณีของคุณไม่มีกลุ่มรหัสของคุณอาจเป็นเช่นนี้:
import re
s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"
r = "am_replace_str"
def repl(match):
_reg = "|".join(match.groups())
return re.sub(_reg, r,match.group(0))
#
re.sub(reg,repl, s)