regex agar cocok, tetapi hanya mengganti sebagian dari pola, dengan python

Aug 17 2020

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

3 Marat Aug 17 2020 at 00:27

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.subakan menggantikan seluruh ekspresi yang cocok, termasuk huruf sebelumnya dan huruf berikutnya.
  • re.findallmasih 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)
2 RyszardCzech Aug 17 2020 at 02:48

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
ShinNShirley Sep 30 2020 at 14:33

Ini re.subakan 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)