regex agar cocok, tetapi hanya mengganti sebagian dari pola, dengan python
Semua contoh yang saya temukan di stack overflow terlalu rumit bagi saya untuk merekayasa balik .
Pertimbangkan contoh mainan ini
s = "asdfasd a_b dsfd"
saya ingin s = "asdfasd a'b dsfd"
Yaitu: temukan dua karakter yang dipisahkan oleh garis bawah dan ganti garis bawah itu dengan apostrof
Mencoba:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
Saya pikir ()
seharusnya menyelesaikan masalah ini?
Yang lebih membingungkan adalah kenyataan bahwa tampaknya kami berhasil menemukan karakter yang ingin kami ganti:
re.findall("[a-z](_)[a-z]",s)
#['_']
mengapa ini tidak diganti?
Terima kasih
Jawaban
Gunakan pola lihat ke depan dan ke belakang:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
Pola lihat ke depan / belakang memiliki lebar nol dan karenanya tidak menggantikan apa pun.
UPD:
- Masalahnya adalah itu
re.sub
akan menggantikan seluruh ekspresi yang cocok, termasuk huruf sebelumnya dan huruf berikutnya. re.findall
masih cocok dengan seluruh ekspresi, tetapi juga memiliki grup (tanda kurung di dalamnya), yang Anda amati. Seluruh pertandingan terhentia_b
- Ekspresi lookahead / lookbehind memeriksa bahwa pencarian diawali / diikuti dengan pola, tapi tidak memasukkannya ke dalam kecocokan.
- pilihan lain adalah membuat beberapa grup, dan menempatkan grup tersebut ke dalam pengganti:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
Saat menggunakan re.sub
, teks yang akan disimpan harus ditangkap, teks yang akan dihapus tidak boleh.
Menggunakan
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
Lihat buktinya .
PENJELASAN
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
Kode Python :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
Keluaran:
asdfasd a'b dsfd
Ini re.sub
akan menggantikan semua yang cocok.
Ada cara yang lebih umum untuk menyelesaikan masalah Anda, dan Anda tidak perlu mengubah ekspresi reguler Anda.
Kode di bawah ini:
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)
keluaran: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
Tentu saja, jika kasus Anda tidak berisi grup, kode Anda mungkin seperti ini:
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)