Regex in Python, aber nur einen Teil des Musters ersetzen
Alle Beispiele, die ich beim Stapelüberlauf gefunden habe, sind zu kompliziert, als dass ich sie rückentwickeln könnte .
Betrachten Sie dieses Spielzeugbeispiel
s = "asdfasd a_b dsfd"
ich möchte s = "asdfasd a'b dsfd"
Das heißt: Suchen Sie zwei durch einen Unterstrich getrennte Zeichen und ersetzen Sie diesen Unterstrich durch einen Apostroph
Versuch:
re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"
Ich dachte die ()sollten dieses Problem lösen?
Noch verwirrender ist die Tatsache, dass wir den Charakter, den wir ersetzen möchten, anscheinend erfolgreich gefunden haben:
re.findall("[a-z](_)[a-z]",s)
#['_']
warum wird das nicht ersetzt?
Vielen Dank
Antworten
Verwenden Sie Vorausschau- und Rückblickmuster:
re.sub("(?<=[a-z])_(?=[a-z])","'",s)
Vorwärts- / Rückwärtsmuster haben eine Breite von Null und ersetzen daher nichts.
UPD:
- Das Problem war, dass
re.subder gesamte übereinstimmende Ausdruck einschließlich des vorhergehenden und des folgenden Buchstabens ersetzt wird. re.findallstimmte immer noch mit dem gesamten Ausdruck überein, hatte aber auch eine Gruppe (die Klammer im Inneren), die Sie beobachtet haben. Das ganze Match war stilla_b- Lookahead / Lookbehind-Ausdrücke prüfen, ob der Suche ein Muster vorausgeht / folgt, schließen es jedoch nicht in die Übereinstimmung ein.
- Eine andere Möglichkeit bestand darin, mehrere Gruppen zu erstellen und diese Gruppen in den Ersatz einzufügen:
re.sub("([a-z])_([a-z])", r"\1'\2", s)
Bei der Verwendung re.submuss der zu behaltende Text erfasst werden, der zu entfernende Text jedoch nicht.
Verwenden
re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)
Siehe Beweis .
ERLÄUTERUNG
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-Code :
import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))
Ausgabe:
asdfasd a'b dsfd
Das re.subwird alles ersetzen, was es gefunden hat.
Es gibt eine allgemeinere Möglichkeit, Ihr Problem zu lösen, und Sie müssen Ihren regulären Ausdruck nicht erneut ändern.
Code unten:
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)
Ausgabe: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'
Wenn Ihr Fall keine Gruppen enthält, kann Ihr Code natürlich folgendermaßen aussehen:
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)