วิธีใช้โมดูลนิพจน์ปกติของ Python re (จับคู่ ค้นหา ย่อย ฯลฯ)

ธุรกิจ

ในการประมวลผลนิพจน์ทั่วไปใน Python เราใช้โมดูล re จากไลบรารีมาตรฐาน ช่วยให้คุณสามารถแยก แทนที่ และแยกสตริงโดยใช้รูปแบบนิพจน์ทั่วไป

ในส่วนนี้ ก่อนอื่นเราจะอธิบายฟังก์ชันและวิธีการของโมดูลใหม่

  • การรวบรวมรูปแบบนิพจน์ทั่วไป:compile()
  • จับคู่วัตถุ
  • ตรวจสอบว่าจุดเริ่มต้นของสตริงตรงกันหรือไม่ แยก:match()
  • ตรวจสอบการแข่งขันไม่ จำกัด เฉพาะจุดเริ่มต้น:search()
  • ตรวจสอบว่าสตริงทั้งหมดตรงกันหรือไม่:fullmatch()
  • รับรายการชิ้นส่วนที่ตรงกันทั้งหมด:findall()
  • รับชิ้นส่วนที่ตรงกันทั้งหมดเป็นตัววนซ้ำ:finditer()
  • แทนที่ส่วนที่ตรงกัน:sub(),subn()
  • การแยกสตริงด้วยรูปแบบนิพจน์ทั่วไป:split()

หลังจากนั้น ฉันจะอธิบายอักขระเมตา (อักขระพิเศษ) และลำดับพิเศษของนิพจน์ทั่วไปที่สามารถใช้ได้ในโมดูล re โดยทั่วไป มันคือไวยากรณ์นิพจน์ทั่วไปมาตรฐาน แต่ระวังเกี่ยวกับการตั้งค่าสถานะ (โดยเฉพาะ re.ASCII)

  • อักขระเมตานิพจน์ทั่วไป ลำดับพิเศษ และคำเตือนใน Python
  • ตั้งธง
    • จำกัดเฉพาะอักขระ ASCII:re.ASCII
    • ไม่คำนึงถึงขนาดตัวพิมพ์:re.IGNORECASE
    • จับคู่จุดเริ่มต้นและจุดสิ้นสุดของแต่ละบรรทัด:re.MULTILINE
    • ระบุหลายแฟล็ก
  • แมตช์โลภและไม่โลภ

รวบรวมรูปแบบนิพจน์ทั่วไป: คอมไพล์ ()

มีสองวิธีในการประมวลผลนิพจน์ทั่วไปในโมดูลใหม่

เรียกใช้ด้วยฟังก์ชั่น

อย่างแรกคือฟังก์ชั่นre.match(),re.sub()ฟังก์ชันในลักษณะนี้พร้อมใช้สำหรับการแยก การแทนที่ และกระบวนการอื่นๆ โดยใช้รูปแบบนิพจน์ทั่วไป

รายละเอียดของฟังก์ชันจะอธิบายในภายหลัง แต่ในอาร์กิวเมนต์ทั้งหมด อาร์กิวเมนต์แรกคือสตริงของรูปแบบนิพจน์ทั่วไป ตามด้วยสตริงที่จะประมวลผลเป็นต้น ตัวอย่างเช่น ใน re.sub() ซึ่งทำการแทนที่ อาร์กิวเมนต์ที่สองคือสตริงการแทนที่ และอาร์กิวเมนต์ที่สามคือสตริงที่จะประมวลผล

import re

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

โปรดทราบว่า [a-z] ในรูปแบบนิพจน์ทั่วไปในตัวอย่างนี้หมายถึงอักขระใดๆ จาก a ถึง z (เช่น อักษรตัวพิมพ์เล็ก) และ + หมายถึง ทำซ้ำรูปแบบก่อนหน้า (ในกรณีนี้ [a-z]) อย่างน้อยหนึ่งครั้ง [a-z]+ จะจับคู่สตริงใดๆ ที่ซ้ำอักขระตัวอักษรตัวพิมพ์เล็กอย่างน้อยหนึ่งตัว

. เป็นอักขระเมตา (อักขระที่มีความหมายพิเศษ) และต้องหลีกหนีด้วยแบ็กสแลช

เนื่องจากสตริงรูปแบบนิพจน์ทั่วไปมักใช้แบ็กสแลชจำนวนมาก จึงสะดวกที่จะใช้สตริงดิบดังในตัวอย่าง

รันในเมธอดของอ็อบเจกต์รูปแบบนิพจน์ทั่วไป

วิธีที่สองในการประมวลผลนิพจน์ทั่วไปในโมดูลใหม่คือวิธีวัตถุรูปแบบนิพจน์ทั่วไป

การใช้ re.compile() คุณสามารถคอมไพล์สตริงรูปแบบนิพจน์ทั่วไปเพื่อสร้างอ็อบเจ็กต์รูปแบบนิพจน์ทั่วไปได้

p = re.compile(r'([a-z]+)@([a-z]+)\.com')

print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')

print(type(p))
# <class 're.Pattern'>

re.match(),re.sub()ตัวอย่างเช่น กระบวนการเดียวกับฟังก์ชันเหล่านี้สามารถดำเนินการเป็นเมธอด match(),sub() ของอ็อบเจ็กต์นิพจน์ทั่วไป

m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

ฟังก์ชัน re.xxx() ทั้งหมดที่อธิบายไว้ด้านล่างนี้ยังถูกจัดให้เป็นเมธอดของอ็อบเจ็กต์นิพจน์ทั่วไป

หากคุณกำลังทำซ้ำกระบวนการที่ใช้รูปแบบเดียวกัน การสร้างอ็อบเจ็กต์นิพจน์ทั่วไปด้วย re.compile() และใช้มันอย่างมีประสิทธิภาพมากกว่า

ในโค้ดตัวอย่างต่อไปนี้ ฟังก์ชันนี้ถูกใช้โดยไม่ต้องคอมไพล์เพื่อความสะดวก แต่ถ้าคุณต้องการใช้รูปแบบเดิมซ้ำๆ ขอแนะนำให้คอมไพล์ล่วงหน้าและรันเป็นเมธอดของอ็อบเจ็กต์นิพจน์ทั่วไป

จับคู่วัตถุ

จับคู่ (), ค้นหา () ฯลฯ ส่งคืนวัตถุที่ตรงกัน

s = 'aaa@xxx.com'

m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(m))
# <class 're.Match'>

ได้สตริงและตำแหน่งที่ตรงกันโดยใช้วิธีการต่อไปนี้ของวัตถุที่ตรงกัน

  • รับตำแหน่งของการแข่งขัน:start(),end(),span()
  • รับสตริงที่ตรงกัน:group()
  • รับสตริงสำหรับแต่ละกลุ่ม:groups()
print(m.start())
# 0

print(m.end())
# 11

print(m.span())
# (0, 11)

print(m.group())
# aaa@xxx.com

หากคุณใส่ส่วนของรูปแบบนิพจน์ทั่วไปไว้ในสตริงที่มีวงเล็บ () ส่วนนั้นจะถูกประมวลผลเป็นกลุ่ม ในกรณีนี้ สตริงของส่วนที่ตรงกับแต่ละกลุ่มในกลุ่ม () สามารถรับได้เป็นทูเพิล

m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.groups())
# ('aaa', 'xxx', 'com')

ตรวจสอบว่าจุดเริ่มต้นของสตริงตรงกันหรือไม่ แยก: match()

match() คืนค่าวัตถุที่ตรงกันหากจุดเริ่มต้นของสตริงตรงกับรูปแบบ

ดังที่กล่าวไว้ข้างต้น สามารถใช้วัตถุที่ตรงกันเพื่อแยกสตริงย่อยที่ตรงกัน หรือเพียงเพื่อตรวจสอบว่ามีการจับคู่หรือไม่

match() จะตรวจสอบจุดเริ่มต้นเท่านั้น หากไม่มีสตริงที่ตรงกันที่จุดเริ่มต้น จะส่งกลับ None

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None

ตรวจสอบการจับคู่ไม่ จำกัด เฉพาะจุดเริ่มต้น แยก: search()

เช่นเดียวกับการจับคู่ () จะส่งกลับวัตถุที่ตรงกันหากตรงกัน

หากมีหลายส่วนที่ตรงกัน จะส่งเฉพาะส่วนที่ตรงกันส่วนแรกเท่านั้น

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

หากคุณต้องการได้ชิ้นส่วนที่ตรงกันทั้งหมด ให้ใช้ findall() หรือ finditer() ตามที่อธิบายไว้ด้านล่าง

ตรวจสอบว่าสตริงทั้งหมดตรงกัน: fullmatch()

หากต้องการตรวจสอบว่าสตริงทั้งหมดตรงกับรูปแบบนิพจน์ทั่วไปหรือไม่ ให้ใช้ fullmatch() สิ่งนี้มีประโยชน์ ตัวอย่างเช่น เพื่อตรวจสอบว่าสตริงนั้นเป็นที่อยู่อีเมลที่ถูกต้องหรือไม่

หากทั้งสตริงตรงกัน วัตถุที่ตรงกันจะถูกส่งคืน

s = 'aaa@xxx.com'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

หากมีชิ้นส่วนที่ไม่ตรงกัน (เฉพาะบางส่วนที่ตรงกันหรือไม่มีการจับคู่เลย) ไม่มีจะถูกส่งคืน

s = '!!!aaa@xxx.com!!!'

m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None

fullmatch() ถูกเพิ่มใน Python 3.4.0 หากคุณต้องการทำเช่นเดียวกันในเวอร์ชันก่อนหน้า ให้ใช้การจับคู่ () และอักขระเมตาที่ตรงกัน $ ในตอนท้าย ถ้าสตริงทั้งหมดตั้งแต่ต้นจนจบไม่ตรงกัน จะส่งกลับ None

s = '!!!aaa@xxx.com!!!'

m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None

รับรายการชิ้นส่วนที่ตรงกันทั้งหมด: findall()

findall() ส่งคืนรายการของสตริงย่อยที่ตรงกันทั้งหมด โปรดทราบว่าองค์ประกอบของรายการไม่ตรงกับวัตถุ แต่เป็นสตริง

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']

สามารถตรวจสอบจำนวนชิ้นส่วนที่ตรงกันได้โดยใช้ฟังก์ชันในตัว len() ซึ่งจะคืนค่าจำนวนองค์ประกอบในรายการ

print(len(result))
# 3

การจัดกลุ่มด้วยวงเล็บ () ในรูปแบบนิพจน์ทั่วไปจะส่งคืนรายการสิ่งอันดับที่มีองค์ประกอบเป็นสตริงของแต่ละกลุ่ม นี่เทียบเท่ากับกลุ่ม () ในวัตถุที่ตรงกัน

result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]

วงเล็บกลุ่ม () สามารถซ้อนได้ ดังนั้นหากคุณต้องการได้ผลลัพธ์ที่ตรงกันทั้งหมดด้วย ให้ใส่การจับคู่ทั้งหมดไว้ในวงเล็บ ()

result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]

หากไม่พบรายการที่ตรงกัน ทูเพิลที่ว่างเปล่าจะถูกส่งกลับ

result = re.findall('[0-9]+', s)
print(result)
# []

รับส่วนที่ตรงกันทั้งหมดเป็นตัววนซ้ำ: finditer()

finditer() ส่งคืนส่วนที่ตรงกันทั้งหมดเป็นตัววนซ้ำ องค์ประกอบไม่ใช่สตริงเช่น findall() แต่จับคู่วัตถุ ดังนั้นคุณสามารถรับตำแหน่ง (ดัชนี) ของส่วนที่ตรงกันได้

ไม่สามารถพิมพ์ตัววนซ้ำด้วย print() เพื่อรับเนื้อหา หากคุณใช้ฟังก์ชัน next() หรือ for ในตัว คุณสามารถรับเนื้อหาได้ทีละรายการ

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>

print(type(result))
# <class 'callable_iterator'>

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

นอกจากนี้ยังสามารถแปลงเป็นรายการด้วย list()

l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]

print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(type(l[0]))
# <class 're.Match'>

print(l[0].span())
# (0, 11)

หากคุณต้องการได้ตำแหน่งของส่วนที่ตรงกันทั้งหมด สัญกรณ์ความเข้าใจรายการจะสะดวกกว่า list()

print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]

ตัววนซ้ำจะนำองค์ประกอบออกตามลำดับ โปรดทราบว่าหากคุณพยายามดึงองค์ประกอบเพิ่มเติมหลังจากถึงจุดสิ้นสุด คุณจะไม่เหลืออะไรเลย

result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)

for m in result:
    print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>

print(list(result))
# []

แทนที่ส่วนที่ตรงกัน: sub(), subn()

การใช้ sub() คุณสามารถแทนที่ส่วนที่ตรงกันด้วยสตริงอื่นได้ สตริงที่แทนที่จะถูกส่งกลับ

s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net

print(type(result))
# <class 'str'>

เมื่อจัดกลุ่มด้วยวงเล็บ () คุณสามารถใช้สตริงที่ตรงกันในสตริงที่แทนที่ได้

โดยค่าเริ่มต้น สิ่งต่อไปนี้ได้รับการสนับสนุน: โปรดทราบว่าสำหรับสตริงปกติที่ไม่ใช่สตริงดิบ แบ็กสแลชต้องแสดงรายการก่อนแบ็กสแลชเพื่อหลีกเลี่ยงการแบ็กสแลช

\1วงเล็บแรก
\2วงเล็บที่สอง
\3วงเล็บที่สาม
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

?P<xxx>
หากคุณตั้งชื่อกลุ่มโดยเขียนไว้ที่จุดเริ่มต้นของวงเล็บของรูปแบบนิพจน์ทั่วไป คุณสามารถระบุกลุ่มโดยใช้ชื่อแทนตัวเลขดังที่แสดงด้านล่าง
\g<xxx>

result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net

จำนวนอาร์กิวเมนต์ระบุจำนวนสูงสุดของการแทนที่ เฉพาะการนับจากด้านซ้ายเท่านั้นที่จะถูกแทนที่

result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net

subn() ส่งกลับ tuple ของสตริงที่ถูกแทนที่ (เหมือนกับค่าส่งคืนของ sub()) และจำนวนของชิ้นส่วนที่ถูกแทนที่ (ตัวเลขที่ตรงกับรูปแบบ)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)

วิธีการระบุอาร์กิวเมนต์เหมือนกับ sub() คุณสามารถใช้ส่วนที่จัดกลุ่มตามวงเล็บ หรือระบุจำนวนอาร์กิวเมนต์

result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)

result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)

การแยกสตริงด้วยรูปแบบนิพจน์ทั่วไป: split()

split() แยกสตริงที่ส่วนที่ตรงกับรูปแบบและส่งคืนเป็นรายการ

โปรดทราบว่าการจับคู่ครั้งแรกและครั้งสุดท้ายจะมีสตริงว่างที่จุดเริ่มต้นและจุดสิ้นสุดของรายการผลลัพธ์

s = '111aaa222bbb333'

result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']

result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']

อาร์กิวเมนต์ maxsplit ระบุจำนวนสูงสุดของการแยก (ชิ้น) จะแยกเฉพาะการนับจากด้านซ้ายเท่านั้น

result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']

อักขระเมตานิพจน์ทั่วไป ลำดับพิเศษ และคำเตือนใน Python

อักขระเมตานิพจน์ทั่วไปหลัก (อักขระพิเศษ) และลำดับพิเศษที่สามารถใช้ได้ในโมดูล Python 3 re มีดังนี้

metacharacterเนื้อหา
.อักขระเดี่ยวใดๆ ที่ไม่ใช่การขึ้นบรรทัดใหม่ (รวมถึงการขึ้นบรรทัดใหม่ด้วยแฟล็ก DOTALL)
^จุดเริ่มต้นของสตริง (ตรงกับจุดเริ่มต้นของแต่ละบรรทัดด้วยแฟล็ก MULTILINE)
$จุดสิ้นสุดของสตริง (ตรงกับจุดสิ้นสุดของแต่ละบรรทัดด้วยแฟล็ก MULTILINE)
*ทำซ้ำรูปแบบก่อนหน้ามากกว่า 0 ครั้ง
+ทำซ้ำรูปแบบก่อนหน้าอย่างน้อยหนึ่งครั้ง
?ทำซ้ำรูปแบบก่อนหน้า 0 หรือ 1 ครั้ง
{m}ทำซ้ำรูปแบบก่อนหน้า m ครั้ง
{m, n}แบบสุดท้าย.m~nทำซ้ำ
[]ชุดอักขระ[]ตรงกับหนึ่งในอักขระเหล่านี้
|หรือA|Bตรงกับรูปแบบ A หรือ B
ลำดับพิเศษเนื้อหา
\dตัวเลขทศนิยม Unicode (จำกัด เฉพาะตัวเลข ASCII โดยแฟล็ก ASCII)
\D\dความหมายตรงกันข้ามกับสิ่งนี้
\sอักขระช่องว่าง Unicode (จำกัด อักขระช่องว่าง ASCII โดยแฟล็ก ASCII)
\S\sความหมายตรงกันข้ามกับสิ่งนี้
\wอักขระคำ Unicode และขีดล่าง (จำกัด เฉพาะอักขระที่เป็นตัวอักษรและตัวเลขคละกัน ASCII และขีดล่างด้วยแฟล็ก ASCII)
\W\wความหมายตรงกันข้ามกับสิ่งนี้

ไม่ใช่ทั้งหมดที่ระบุไว้ในตารางนี้ ดูเอกสารอย่างเป็นทางการสำหรับรายการทั้งหมด

โปรดทราบว่าความหมายบางอย่างแตกต่างกันใน Python 2

ตั้งธง

ตามที่แสดงในตารางด้านบน อักขระเมตาบางตัวและลำดับพิเศษจะเปลี่ยนโหมดตามแฟล็ก

เฉพาะธงหลักเท่านั้นที่จะครอบคลุมที่นี่ ดูเอกสารอย่างเป็นทางการสำหรับส่วนที่เหลือ

จำกัดอักขระ ASCII: re.ASCII

\wซึ่งจะจับคู่คันจิแบบไบต์คู่ อักขระที่เป็นตัวอักษรและตัวเลขคละกัน ฯลฯ โดยค่าเริ่มต้นสำหรับสตริง Python 3 ไม่เทียบเท่ากับสิ่งต่อไปนี้ เนื่องจากไม่ใช่นิพจน์ทั่วไปมาตรฐาน[a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None

หากคุณระบุ re.ASCII สำหรับแฟล็กอาร์กิวเมนต์ในแต่ละฟังก์ชัน หรือเพิ่มแฟล็กอินไลน์ต่อไปนี้ที่จุดเริ่มต้นของสตริงรูปแบบนิพจน์ทั่วไป จะจับคู่เฉพาะอักขระ ASCII (จะไม่จับคู่ภาษาญี่ปุ่นแบบดับเบิลไบต์ อักขระที่เป็นตัวอักษรและตัวเลขคละกัน ฯลฯ .)
(?a)
ในกรณีนี้ สองต่อไปนี้จะเท่ากัน
\w#ERROR![a-zA-Z0-9_]

m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None

m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None

เช่นเดียวกับการคอมไพล์ด้วย re.compile() ใช้แฟล็กอาร์กิวเมนต์หรือแฟล็กอินไลน์

p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)

print(p.match('漢字ABC123'))
# None

ASCII ยังมีให้ในรูปแบบสั้นอีกครั้ง ก. คุณสามารถใช้อย่างใดอย่างหนึ่ง

print(re.ASCII is re.A)
# True

\W ซึ่งตรงกันข้ามกับ \W ก็ได้รับผลกระทบจาก re.ASCII และแฟล็กอินไลน์ด้วยเช่นกัน

m = re.match(r'\W+', '漢字ABC123')
print(m)
# None

m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>

เช่นเดียวกับ \w อักขระสองตัวต่อไปนี้จะจับคู่อักขระทั้งแบบไบต์เดี่ยวและแบบไบต์คู่โดยค่าเริ่มต้น แต่จะถูกจำกัดที่อักขระแบบไบต์เดี่ยว หากระบุ re.ASCII หรือแฟล็กอินไลน์ไว้

  • จับคู่ตัวเลข\d
  • ตรงกับช่องว่าง\s
  • ตรงกับที่ไม่ใช่ตัวเลข\D
  • ตรงกับที่ไม่ใช่ช่องว่าง\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>

m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None

m = re.match(r'\s+', ' ')  # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>

m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None

ไม่คำนึงถึงขนาดตัวพิมพ์:re.IGNORECASE

โดยค่าเริ่มต้น จะคำนึงถึงขนาดตัวพิมพ์ หากต้องการจับคู่ทั้งสอง คุณต้องใส่ทั้งตัวพิมพ์ใหญ่และตัวพิมพ์เล็กในรูปแบบ

re.IGNORECASEหากระบุสิ่งนี้ จะจับคู่โดยไม่พิจารณาตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ เทียบเท่ากับแฟล็ก i ในนิพจน์ทั่วไปมาตรฐาน

m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>

คุณสามารถใช้น้อยกว่าหรือเท่ากับ

  • ธงแบบอินไลน์(?i)
  • ตัวย่อre.I

จับคู่จุดเริ่มต้นและจุดสิ้นสุดของแต่ละบรรทัด:re.MULTILINE

^อักขระเมตาในนิพจน์ทั่วไปนี้ตรงกับจุดเริ่มต้นของสตริง

โดยค่าเริ่มต้น ระบบจะจับคู่เฉพาะจุดเริ่มต้นของทั้งสตริงเท่านั้น แต่รายการต่อไปนี้จะจับคู่กับจุดเริ่มต้นของแต่ละบรรทัดด้วย เทียบเท่ากับแฟล็ก m ในนิพจน์ทั่วไปมาตรฐาน
re.MULTILINE

s = '''aaa-xxx
bbb-yyy
ccc-zzz'''

print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz

result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']

result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']

result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']

$ตรงกับส่วนท้ายของสตริง โดยค่าเริ่มต้น จะจับคู่เฉพาะส่วนท้ายของสตริงทั้งหมดเท่านั้น
re.MULTILINEหากคุณระบุสิ่งนี้ จะตรงกับจุดสิ้นสุดของแต่ละบรรทัดด้วย

result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']

result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']

คุณสามารถใช้น้อยกว่าหรือเท่ากับ

  • ธงแบบอินไลน์(?m)
  • ตัวย่อre.M

ระบุหลายแฟล็ก

|หากคุณต้องการเปิดใช้งานหลายแฟล็กพร้อมกัน ให้ใช้สิ่งนี้ ในกรณีของอินไลน์แฟล็ก อักขระแต่ละตัวจะต้องตามด้วยตัวอักษรตามที่แสดงด้านล่าง
(?am)

s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''

print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz

result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']

result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']

result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']

แมตช์โลภและไม่โลภ

นี่เป็นปัญหาทั่วไปของนิพจน์ทั่วไป ไม่ใช่แค่ปัญหากับ Python แต่ฉันจะเขียนเกี่ยวกับมันเพราะมันมักจะทำให้ฉันมีปัญหา

โดยค่าเริ่มต้น รายการต่อไปนี้คือการจับคู่ที่โลภ ซึ่งตรงกับสตริงที่ยาวที่สุด

  • *
  • +
  • ?
s = 'aaa@xxx.com, bbb@yyy.com'

m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>

print(m.group())
# aaa@xxx.com, bbb@yyy.com

NS ? หลังจากนั้นจะส่งผลให้เกิดการจับคู่น้อยที่สุดที่ไม่โลภการจับคู่สตริงที่สั้นที่สุด

  • *?
  • +?
  • ??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>

print(m.group())
# aaa@xxx.com

โปรดทราบว่าการจับคู่โลภเริ่มต้นอาจตรงกับสตริงที่ไม่คาดคิด