ในการประมวลผลนิพจน์ทั่วไปใน Python เราใช้โมดูล re จากไลบรารีมาตรฐาน ช่วยให้คุณสามารถแยก แทนที่ และแยกสตริงโดยใช้รูปแบบนิพจน์ทั่วไป
- re — Regular expression operations — Python 3.10.0 Documentation
- Regular Expression HOWTO — Python 3.10.0 Documentation
ในส่วนนี้ ก่อนอื่นเราจะอธิบายฟังก์ชันและวิธีการของโมดูลใหม่
- การรวบรวมรูปแบบนิพจน์ทั่วไป:
compile()
- จับคู่วัตถุ
- ตรวจสอบว่าจุดเริ่มต้นของสตริงตรงกันหรือไม่ แยก:
match()
- ตรวจสอบการแข่งขันไม่ จำกัด เฉพาะจุดเริ่มต้น:
search()
- ตรวจสอบว่าสตริงทั้งหมดตรงกันหรือไม่:
fullmatch()
- รับรายการชิ้นส่วนที่ตรงกันทั้งหมด:
findall()
- รับชิ้นส่วนที่ตรงกันทั้งหมดเป็นตัววนซ้ำ:
finditer()
- แทนที่ส่วนที่ตรงกัน:
sub()
,subn()
- การแยกสตริงด้วยรูปแบบนิพจน์ทั่วไป:
split()
หลังจากนั้น ฉันจะอธิบายอักขระเมตา (อักขระพิเศษ) และลำดับพิเศษของนิพจน์ทั่วไปที่สามารถใช้ได้ในโมดูล re โดยทั่วไป มันคือไวยากรณ์นิพจน์ทั่วไปมาตรฐาน แต่ระวังเกี่ยวกับการตั้งค่าสถานะ (โดยเฉพาะ re.ASCII)
- อักขระเมตานิพจน์ทั่วไป ลำดับพิเศษ และคำเตือนใน Python
- ตั้งธง
- จำกัดเฉพาะอักขระ ASCII:
re.ASCII
- ไม่คำนึงถึงขนาดตัวพิมพ์:
re.IGNORECASE
- จับคู่จุดเริ่มต้นและจุดสิ้นสุดของแต่ละบรรทัด:
re.MULTILINE
- ระบุหลายแฟล็ก
- จำกัดเฉพาะอักขระ ASCII:
- แมตช์โลภและไม่โลภ
- รวบรวมรูปแบบนิพจน์ทั่วไป: คอมไพล์ ()
- จับคู่วัตถุ
- ตรวจสอบว่าจุดเริ่มต้นของสตริงตรงกันหรือไม่ แยก: match()
- ตรวจสอบการจับคู่ไม่ จำกัด เฉพาะจุดเริ่มต้น แยก: search()
- ตรวจสอบว่าสตริงทั้งหมดตรงกัน: fullmatch()
- รับรายการชิ้นส่วนที่ตรงกันทั้งหมด: findall()
- รับส่วนที่ตรงกันทั้งหมดเป็นตัววนซ้ำ: finditer()
- แทนที่ส่วนที่ตรงกัน: sub(), subn()
- การแยกสตริงด้วยรูปแบบนิพจน์ทั่วไป: split()
- อักขระเมตานิพจน์ทั่วไป ลำดับพิเศษ และคำเตือนใน Python
- ตั้งธง
- แมตช์โลภและไม่โลภ
รวบรวมรูปแบบนิพจน์ทั่วไป: คอมไพล์ ()
มีสองวิธีในการประมวลผลนิพจน์ทั่วไปในโมดูลใหม่
เรียกใช้ด้วยฟังก์ชั่น
อย่างแรกคือฟังก์ชั่น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
โปรดทราบว่าการจับคู่โลภเริ่มต้นอาจตรงกับสตริงที่ไม่คาดคิด