Bagaimana cara menggunakan variabel di dalam ekspresi reguler?

235

Saya ingin menggunakan variabledi dalam regex, bagaimana saya bisa melakukan ini Python?

TEXTO = sys.argv[1]

if re.search(r"\b(?=\w)TEXTO\b(?!\w)", subject, re.IGNORECASE):
    # Successful match
else:
    # Match attempt failed
HUBUNGI19
sumber
9
Anda menggunakan penggabungan string
Chris Eberle

Jawaban:

52

Dari python 3.6 pada Anda juga dapat menggunakan Interpolasi String Literal , "f-string". Dalam kasus khusus Anda solusinya adalah:

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

EDIT:

Karena ada beberapa pertanyaan dalam komentar tentang bagaimana menangani karakter khusus, saya ingin memperluas jawaban saya:

string mentah ('r'):

Salah satu konsep utama yang harus Anda pahami ketika berhadapan dengan karakter khusus dalam ekspresi reguler adalah untuk membedakan antara string literal dan ekspresi reguler itu sendiri. Dijelaskan dengan sangat baik di sini :

Pendeknya:

Katakanlah alih-alih menemukan batas kata \bsetelah TEXTOAnda ingin mencocokkan string \boundary. Anda harus menulis:

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

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

Ini hanya berfungsi karena kita menggunakan string mentah (regex didahului oleh 'r'), jika tidak kita harus menulis "batas" di regex (empat garis miring terbalik). Selain itu, tanpa '\ r', \ b 'tidak akan dikonversi menjadi batas kata lagi tetapi menjadi backspace!

re.escape :

Pada dasarnya menempatkan backspace di depan karakter khusus apa pun. Karenanya, jika Anda mengharapkan karakter khusus di TEXTO, Anda perlu menulis:

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

CATATAN: Untuk versi> = python 3.7: !, ", %, ', ,, /, :, ;, <, =, >, @, dan `tidak melarikan diri. Hanya karakter khusus dengan makna dalam regex yang masih lolos. _tidak lolos sejak Python 3.3. (s. di sini )

Kurung kurawal:

Jika Anda ingin menggunakan penjumlah dalam ekspresi reguler menggunakan f-string, Anda harus menggunakan kurung kurawal ganda. Katakanlah Anda ingin mencocokkan TEXTO diikuti oleh tepat 2 digit:

if re.search(rf"\b(?=\w){re.escape(TEXTO)}\d{{2}}\b(?!\w)", subject, re.IGNORECASE):
    print("match")
di udara
sumber
2
Pada 2020, ini adalah cara paling sederhana dan paling pythonic untuk menggunakan variabel di dalam ekspresi reguler
CONvid19
3
Ini jelas merupakan WOW .
Jason Goal
2
seseorang dapat menjelaskan pentingnya "rf" di sini
Harsha Reddy
1
@HarshaReddy: 'r': String ini adalah string mentah: Jika Anda tidak menggunakannya, '\ b' akan dikonversi ke karakter backspace ( docs.python.org/3/howto/regex.html#more- pola-kekuatan ). 'f' memberi tahu python bahwa ini adalah 'f-string', s. tautan di atas, dan memungkinkan Anda untuk menulis variabel ke kurung kurawal-
udara
2
Bagaimana menulis bilangan di f-string: fr"foo{{1,5}}"(ganda kawat gigi)
PunchyRascal
281

Anda harus membangun regex sebagai string:

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

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

Perhatikan penggunaan re.escapesehingga jika teks Anda memiliki karakter khusus, mereka tidak akan diartikan demikian.

Ned Batchelder
sumber
4
Bagaimana jika variabel Anda duluan? r'' + foo + 'bar'?
deed02392
@ deed02392 r''tidak perlu jika Anda melakukannya re.escape(foo), yang seharusnya Anda lakukan. Sebenarnya, saya pikir remenafsirkan apa pun yang diberikan sebagai string unicode terlepas dari apakah Anda awalan ratau tidak.
OJFord
Apakah .format () berfungsi dengan baik di tempat re.escape atau apakah re.escape () diperlukan?
Praxiteles
@praxiteles apakah Anda menemukan jawabannya?
CONvid19
2
Saya tidak yakin apakah ini berfungsi di Saya perlu memiliki grup yang variabelnya merupakan bagian dari. Jawaban lain di bawah ini terlihat lebih intuitif untuk itu, dan jangan memecah regex menjadi beberapa ekspresi.
guival
48
if re.search(r"\b(?<=\w)%s\b(?!\w)" % TEXTO, subject, re.IGNORECASE):

Ini akan memasukkan apa yang ada di TEXTO ke dalam regex sebagai string.

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

Saya merasa sangat nyaman untuk membangun pola ekspresi reguler dengan merangkai beberapa pola yang lebih kecil.

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)

Keluaran:

[('begin', 'id1'), ('middl', 'id2')]
Deepak Nagarajan
sumber
4

Saya setuju dengan semua hal di atas kecuali:

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

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

Anda tidak ingin menggunakannya re.escape, karena dalam hal ini Anda ingin berperilaku seperti regex

TEXTO = sys.argv[1]

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

Saya perlu mencari nama pengguna yang mirip satu sama lain, dan apa yang dikatakan Ned Batchelder sangat membantu. Namun, saya menemukan saya memiliki keluaran yang lebih bersih ketika saya menggunakan re.compile untuk membuat istilah pencarian ulang saya:

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

Output dapat dicetak menggunakan yang berikut:

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
sumber
1

Anda dapat mencoba penggunaan lain menggunakan formatgrammer suger:

re_genre = r'{}'.format(your_variable)
regex_pattern = re.compile(re_genre)  
Kevin Chou
sumber
0

Anda juga dapat menggunakan kata kunci format untuk metode ini. Metode keset akan menggantikan {} placeholder ke variabel yang Anda berikan ke metode format sebagai argumen.

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

lebih banyak contoh

Saya memiliki configus.yml dengan aliran file

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

dalam kode python saya gunakan

data_time_real_file=re.findall(r""+flows[flow]["pattern"][0]+"", latest_file)
Nikolay Baranenko
sumber