Как использовать переменную внутри регулярного выражения?

235

Я хотел бы использовать variableвнутри regex, как я могу сделать это внутри Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
CONvid19
источник
9
Вы используете конкатенацию строк
Крис Эберле

Ответы:

52

Начиная с версии Python 3.6 вы также можете использовать интерполяцию литеральных строк , "f-strings". В вашем конкретном случае решение будет:

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

РЕДАКТИРОВАТЬ:

Поскольку в комментарии было несколько вопросов о том, как обращаться со специальными символами, я бы хотел расширить свой ответ:

необработанные строки ('r'):

При работе со специальными символами в регулярных выражениях вы должны понимать одну из основных концепций - различать строковые литералы и само регулярное выражение. Это очень хорошо объяснено здесь :

Коротко:

Допустим, вместо нахождения границы слова \bпосле TEXTOтого, как вы хотите сопоставить строку \boundary. Вы должны написать:

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

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

Это работает только потому, что мы используем необработанную строку (регулярному выражению предшествует 'r'), в противном случае мы должны написать "\\\\ border" в регулярном выражении (четыре обратные косые черты). Кроме того, без '\ r', \ b 'больше не будет преобразовываться в границу слова, но будет в забой!

re.escape :

По сути, ставит пробел перед любым специальным персонажем. Следовательно, если вы ожидаете специального символа в TEXTO, вам нужно написать:

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

Примечание: Для любой версии> = питон 3.7 !, ", %, ', ,, /, :, ;, <, =, >, @, и `не убежали. Только специальные символы со значением в регулярном выражении по-прежнему экранируются. _не удалось избежать начиная с Python 3.3. ( здесь )

Фигурные скобки:

Если вы хотите использовать квантификаторы в регулярном выражении с использованием f-строк, вы должны использовать двойные фигурные скобки. Допустим, вы хотите сопоставить TEXTO, за которым следуют ровно 2 цифры:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")
бортовой
источник
2
Начиная с 2020 года это самый простой и самый питонический способ использования переменной внутри регулярного выражения
CONvid19
3
Это определенно ВАУ .
Джейсон Гол
2
может кто-то объяснить значение «рф» здесь
Харша Редди
1
@HarshaReddy: 'r': эта строка является необработанной строкой: если вы ее не используете, '\ b' будет преобразован в символ возврата на одну позицию ( docs.python.org/3/howto/regex.html#more- образец силы ). 'f' говорит Python, что это 'f-строка', s. ссылка выше, и позволяет записать переменную в фигурные скобки
воздухе
2
Как писать квантификаторы в f-строках: fr"foo{{1,5}}"(двойные скобки)
PunchyRascal
281

Вы должны построить регулярное выражение в виде строки:

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

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

Обратите внимание на использование re.escapeтак, чтобы, если ваш текст имеет специальные символы, они не будут интерпретироваться как таковые.

Нед Бэтчелдер
источник
4
Что если ваша переменная идет первой? r'' + foo + 'bar'?
deed02392
@ deed02392 r''не нужно, если вы делаете re.escape(foo), что вы все равно должны. На самом деле, я думаю, reчто все, что дано, интерпретируется как строка в юникоде, независимо от того, префикс вы rили нет.
OJFord
Работает ли .format () также вместо re.escape или re.escape () необходим?
Praxiteles
@praxiteles ты нашел ответ?
CONvid19
2
Я не уверен, если это работает, мне нужно иметь группу, частью которой является переменная. Другие ответы ниже выглядят более интуитивно понятными и не разбивают регулярное выражение на несколько выражений.
Гиваль
48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Это вставит то, что в TEXTO, в регулярное выражение в виде строки.

Бо Бьюкенен
источник
6

Я считаю очень удобным построить шаблон регулярного выражения, соединив несколько небольших шаблонов.

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)

Вывод:

[('begin', 'id1'), ('middl', 'id2')]
Дипак Нагараджан
источник
4

Я согласен со всем вышеперечисленным, если:

sys.argv[1] было что-то вроде Chicken\d{2}-\d{2}An\s*important\s*anchor

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

вы не хотели бы использовать re.escape, потому что в этом случае вы хотели бы, чтобы он вел себя как регулярное выражение

TEXTO = sys.argv[1]

if re.search(r"\b(?<=\w)" + TEXTO + "\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
Макс Кэрролл
источник
2

Мне нужно было искать имена пользователей, которые похожи друг на друга, и то, что сказал Нед Батчелдер, было невероятно полезным. Тем не менее, я обнаружил, что у меня был более чистый вывод, когда я использовал re.compile для создания моего поискового запроса:

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

Вывод может быть распечатан с использованием следующего:

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
источник
1

Вы можете попробовать другое использование, используя formatgrager suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  
Кевин Чоу
источник
0

Вы также можете использовать ключевое слово format для этого метода .Format заменит {} местозаполнителем переменной, которую вы передали методу формата в качестве аргумента.

if re.search(r"\b(?=\w)**{}**\b(?!\w)".**format(TEXTO)**, subject, re.IGNORECASE):
    # Successful match**strong text**
else:
    # Match attempt failed
Ханиф Мохаммед
источник
0

еще пример

У меня есть configus.yml с файлами потоков

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

в коде Python я использую

data_time_real_file=re.findall(r""+flows[flow]["pattern"][0]+"", latest_file)
Николай Бараненко
источник