Jak używać zmiennej w wyrażeniu regularnym?

235

Chciałbym skorzystać z variablewnętrza regex, jak mogę to zrobić Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
CONvid19
źródło
9
Używasz konkatenacji łańcuchów
Chris Eberle

Odpowiedzi:

52

Począwszy od Pythona 3.6 możesz także używać interpolacji ciągów literalnych , „f-string”. W twoim szczególnym przypadku rozwiązaniem byłoby:

if re.search(rf"\b(?=\w){TEXTO}\b(?!\w)", subject, re.IGNORECASE):
    ...do something

EDYTOWAĆ:

Ponieważ w komentarzu pojawiło się kilka pytań dotyczących postępowania ze znakami specjalnymi, chciałbym rozszerzyć swoją odpowiedź:

nieprzetworzone ciągi („r”):

Jednym z głównych pojęć, które należy zrozumieć, posługując się znakami specjalnymi w wyrażeniach regularnych, jest rozróżnienie literałów łańcuchowych od samego wyrażenia regularnego. Jest to bardzo dobrze wyjaśnione tutaj :

W skrócie:

Powiedzmy, zamiast znaleźć granicę słowa \bpo TEXTOtym, jak chcesz dopasować ciąg \boundary. Musisz napisać:

TEXTO = "Var"
subject = r"Var\boundary"

if re.search(rf"\b(?=\w){TEXTO}\\boundary(?!\w)", subject, re.IGNORECASE):
    print("match")

Działa to tylko dlatego, że używamy nieprzetworzonego ciągu (wyrażenie regularne jest poprzedzone przez „r”), w przeciwnym razie musimy napisać „\\\\ granica” w wyrażeniu regularnym (cztery odwrotne ukośniki). Dodatkowo bez „\ r”, \ b ”nie zamieniłoby się już w granicę słów, ale w backspace!

re.escape :

Zasadniczo stawia backspace przed każdą postacią specjalną. Dlatego jeśli oczekujesz specjalnego znaku w TEXTO, musisz napisać:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\b(?!\w)", subject, re.IGNORECASE):
    print("match")

UWAGA: Dla każdej wersji> = python 3.7: !, ", %, ', ,, /, :, ;, <, =, >, @, i `nie uciekł. Jedynie znaki specjalne mające znaczenie w wyrażeniu regularnym są nadal usuwane. _nie jest uciekany od Pythona 3.3. (s. tutaj )

Nawiasy klamrowe:

Jeśli chcesz używać kwantyfikatorów w wyrażeniu regularnym za pomocą f-stringów, musisz użyć podwójnych nawiasów klamrowych. Powiedzmy, że chcesz dopasować TEXTO, a następnie dokładnie 2 cyfry:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")
samolotowy
źródło
2
Począwszy od 2020 r. Jest to najprostszy i najbardziej pytoniczny sposób użycia zmiennej w wyrażeniu regularnym
CONvid19
3
To zdecydowanie WOW .
Jason Gol
2
czy ktoś może tutaj wyjaśnić znaczenie „rf”
Harsha Reddy
1
@HarshaReddy: 'r': Ten ciąg jest ciągiem surowym: jeśli go nie użyjesz, \ b b zostanie przekonwertowany na znak backspace ( docs.python.org/3/howto/regex.html#more- moc wzorcowa ). „f” mówi pythonowi, że jest to „f-string”, s. link powyżej i umożliwia zapisanie zmiennej w nawiasach klamrowych
powietrzu
2
Jak pisać kwantyfikatory w f-stringach: fr"foo{{1,5}}"(podwoić nawiasy klamrowe)
PunchyRascal
281

Musisz zbudować wyrażenie regularne jako ciąg:

TEXTO = sys.argv[1]
my_regex = r"\b(?=\w)" + re.escape(TEXTO) + r"\b(?!\w)"

if re.search(my_regex, subject, re.IGNORECASE):
    etc.

Zwróć uwagę na użycie re.escape, aby jeśli twój tekst zawiera znaki specjalne, nie będą one interpretowane jako takie.

Ned Batchelder
źródło
4
Co jeśli twoja zmienna jest pierwsza? r'' + foo + 'bar'?
deed02392,
@ deed02392 r''nie jest konieczne, jeśli to zrobisz re.escape(foo), co i tak powinieneś. Właściwie myślę, że reinterpretuje wszystko, co podano jako ciąg Unicode, niezależnie od tego, czy jest to prefiks, rczy nie.
OJFord,
Czy .format () działa również zamiast re.escape, czy też jest wymagana re.escape ()?
Praxiteles,
@praxiteles znalazłeś odpowiedź?
CONvid19,
2
Nie jestem pewien, czy to działa, muszę mieć grupę, której zmienna jest częścią. Inne odpowiedzi poniżej wyglądają na bardziej intuicyjne i nie dzielą wyrażenia regularnego na kilka wyrażeń.
gitarzysta
48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Spowoduje to wstawienie tego, co jest w TEXTO do wyrażenia regularnego jako łańcucha.

Bo Buchanan
źródło
37
rx = r'\b(?<=\w){0}\b(?!\w)'.format(TEXTO)
Cat Plus Plus
źródło
6

Uważam, że bardzo wygodne jest zbudowanie wzorca wyrażenia regularnego poprzez połączenie wielu mniejszych wzorców.

import re

string = "begin:id1:tag:middl:id2:tag:id3:end"
re_str1 = r'(?<=(\S{5})):'
re_str2 = r'(id\d+):(?=tag:)'
re_pattern = re.compile(re_str1 + re_str2)
match = re_pattern.findall(string)
print(match)

Wynik:

[('begin', 'id1'), ('middl', 'id2')]
Deepak Nagarajan
źródło
4

Zgadzam się ze wszystkimi powyższymi, chyba że:

sys.argv[1] było coś w rodzaju Chicken\d{2}-\d{2}An\s*important\s*anchor

sys.argv[1] = "Chicken\d{2}-\d{2}An\s*important\s*anchor"

nie chciałbyś używać re.escape, ponieważ w takim przypadku chciałbyś, aby zachowywał się jak wyrażenie regularne

TEXTO = sys.argv[1]

if re.search(r"\b(?<=\w)" + TEXTO + "\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
Max Carroll
źródło
2

Musiałem wyszukać nazwy użytkowników, które są do siebie podobne, a to, co powiedział Ned Batchelder, było niezwykle pomocne. Odkryłem jednak, że miałem czystsze dane wyjściowe, gdy użyłem re.compile, aby utworzyć termin ponownego wyszukiwania:

pattern = re.compile(r"("+username+".*):(.*?):(.*?):(.*?):(.*)"
matches = re.findall(pattern, lines)

Dane wyjściowe można wydrukować za pomocą:

print(matches[1]) # prints one whole matching line (in this case, the first line)
print(matches[1][3]) # prints the fourth character group (established with the parentheses in the regex statement) of the first line.
jdelaporte
źródło
1

możesz spróbować innego użycia za pomocą formatgramatyki suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  
Kevin Chou
źródło
0

W tym przypadku można również użyć słowa kluczowego format.Format zastąpi symbol zastępczy {} zmienną przekazaną do metody format jako argument.

if re.search(r"\b(?=\w)**{}**\b(?!\w)".**format(TEXTO)**, subject, re.IGNORECASE):
    # Successful match**strong text**
else:
    # Match attempt failed
Haneef Mohammed
źródło
0

więcej przykładów

Mam configus.yml z plikami przepływów

"pattern":
  - _(\d{14})_
"datetime_string":
  - "%m%d%Y%H%M%f"

w kodzie Pythona używam

data_time_real_file=re.findall(r""+flows[flow]["pattern"][0]+"", latest_file)
Nikołaj Baranenko
źródło