eşleştirmek için regex, ancak python'da kalıbın yalnızca bir kısmını değiştirin

Aug 17 2020

Yığın taşmasıyla ilgili bulduğum tüm örnekler , tersine mühendislik yapamayacak kadar karmaşık .

Bu oyuncak örneğini düşünün

s = "asdfasd a_b dsfd"

İstiyorum s = "asdfasd a'b dsfd"

Yani: alt çizgiyle ayrılmış iki karakter bulun ve bu alt çizgiyi kesme işaretiyle değiştirin

Girişim:

re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"

()Bu sorunu çözmesi gerektiğini sanıyordum.

Daha da kafa karıştırıcı, değiştirmek istediğimiz karakteri başarıyla bulduğumuz gerçeğidir:

re.findall("[a-z](_)[a-z]",s)
#['_']

bu neden değiştirilmiyor?

Teşekkürler

Yanıtlar

3 Marat Aug 17 2020 at 00:27

İleriye dönük ve arkaya bakma kalıplarını kullanın:

re.sub("(?<=[a-z])_(?=[a-z])","'",s)

İleriye / arkaya bak desenleri sıfır genişliğe sahiptir ve bu nedenle hiçbir şeyin yerini almaz.

UPD:

  • Sorun, re.subönceki ve sonraki harf dahil olmak üzere tüm eşleşen ifadenin yerini alacak olmasıdır.
  • re.findallhala tüm ifadeyle eşleşiyordu, ancak aynı zamanda gözlemlediğiniz bir grubu (içinde parantez) vardı. Bütün maç halaa_b
  • Lookahead / lookbehind ifadeleri, aramanın önünde / arkasında bir kalıp olduğunu kontrol eder, ancak bunu eşleşmeye dahil etmez.
  • başka bir seçenek de birkaç grup oluşturmak ve bu grupları yerine koymaktı: re.sub("([a-z])_([a-z])", r"\1'\2", s)
2 RyszardCzech Aug 17 2020 at 02:48

Kullanılırken saklanacak re.submetin yakalanmalı, kaldırılacak metin alınmamalıdır.

Kullanım

re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)

Kanıtı görün .

AÇIKLAMA

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 kodu :

import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))

Çıktı:

asdfasd a'b dsfd
ShinNShirley Sep 30 2020 at 14:33

re.subO eşleşti her şeyi değiştirecektir.

Sorununuzu çözmenin daha genel bir yolu vardır ve normal ifadenizi yeniden değiştirmeniz gerekmez.

Aşağıdaki kod:

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)

çıktı: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'

Elbette, vakanız gruplar içermiyorsa, kodunuz şöyle olabilir:

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)