รอบนี้จะมาดูในส่วนของตัวpatternกัน ว่าเราปรับเพิ่มเติมอะไรได้
Grouping Patterns
Number Group
import re
text = 'kalyan roll number is cs1004'
pattern = '(cs)(\d\d\d\d)'
regex = re.compile(pattern)
result = regex.search(text)
print(result.group()) #cs1004 default -> .group(0)
print(result.group(0)) #cs1004
print(result.group(1)) #cs
print(result.group(2)) #1004
print(result.groups())
#('cs', '1004') output is <class 'tuple'>
จากจากตัวอย่างข้างบนจะเห็นว่ามีpattern = ‘(cs)(\d\d\d\d)’ ซึ่งตรงนี้มันเป็นการแบ่งกลุ่มในการค้นหาอีกที (cs)เป็นกลุ่มที่1 (\d\d\d\d)เป็นกลุ่มที่2 แต่ในการค้นหาต้องการข้อความที่ทั้ง2กลุ่มนี้อยู่ติดกัน จากตัวอย่างนี้ลองเอาไปใช้กับโจทย์ที่ต้องการหาตัวเลขที่มีตัวอักษร “cs”ประกบอยู่ด้านหน้า แต่หากเราไม่ต้องการตัวอักษร “cs” ก็สามารถเลือกเอาเฉพาะgroup 2 ที่เป็นตัวเลขได้
Name Group
import re
text = 'kalyan roll number is cs1004'
pattern = r'(?P<branch>cs)(?P<roll>\d\d\d\d)'
regex = re.compile(pattern)
result = regex.search(text)
print(result.group()) #cs1004
print(result.group(0)) #cs1004
print(result.group(1)) #cs
print(result.group("branch")) #cs
print(result.group(2)) #1004
print(result.group("roll")) #1004
print(type(result.groups())) #('cs', '1004') output is <class 'tuple'>
concept เดียวกับอันก่อนหน้า แต่เราสามารถตั้งชื่อให้กับgroupได ้ดูแล้วสื่อความหมายได้มากกว่า โดยเพิ่ม “?P<ชื่อของกลุ่ม>” เข้าไปในวงเล็บของกลุ่มนั้น
จากตัวอย่าง สามารถเพิ่มความหยืดหยุ่นได้เป็น
branch = 'branch'
roll = 'roll'
pattern = r'(?P<'+branch+'>cs)(?P<'+roll+'>\d\d\d\d)'
regex = re.compile(pattern)print(result.group(branch)) #cs
print(result.group(roll)) #1004
Non-Capturing Group
import re
text = 'My personal number is 032-456789 and my office number is 090-142536'
pattern1 = '\d\d\d-\d\d\d\d\d\d'
regex = re.compile(pattern1)
number = regex.findall(text)
print(number) #['032-456789', '090-142536']
regex = re.compile(pattern='(\d\d\d)-(\d\d\d\d\d\d)')
number = regex.findall(text)
print(number) #[('032', '456789'), ('090', '142536')]
regex = re.compile(pattern='(?:\d\d\d)-(?:\d\d\d\d\d\d)')
number = regex.findall(text)
print(number) #['032-456789', '090-142536']
มาดูตัว pattern=’(?:\d\d\d)-(?:\d\d\d\d\d\d)’ จะเห็นว่ามีเครื่องหมาย “ ?: ” อยู่ในgroupด้วย จะเห็นความแตกต่างคือ ตัวที่เป็นgroupธรรมดาจะreturn tupleกลับมาแต่ตัวนี้ return list หรือก็คือมันนำเอาผลลัพท์ของgroup(1)+group(2)แล้วจึง return กลับมา และผลลัพท์นี้เอาไปทำการแก้ไขและนำไปใช้งานได้สะดวกกว่าแบบที่ 2
Multi-character Patterns
Meta character
| (pipe) ใช้กำกับความหมาย“หรือ”
? (question mark) ศูนย์หรือหนึ่งตัว คือจะมีก็ได้ไม่มีก็ได้ แต่ถ้ามีจะมีแค่ตัวเดียว
* (Asterisk)ศูนย์หรือมากว่า
+ ( Plus)หนึ่งหรือมากว่า
. (dot) ตัวอักษรอะไรก็ได้ ยกเว้น\n
มาดูตัวอย่างกันดีกว่า
pipe
ถ้าข้อมูลเป็นแบบด้านบน แล้วเราต้องการตัวเลข แต่ว่าตัวเลขนั้นมีทั้ง2หลักแล3หลัก.
pattern = r'\b(\d{2}|\d{3})\b'
regex = re.compile(pattern)
numbers = regex.findall(text)
print(numbers) #['44', '550', '404', '70']
\b หมายถึงการเว้นวรรค \d หมายถึงตัวเลข \d{2} มีค่าเท่ากับ \d\d
pattern = r'\b(\d{2}|\d{3})\b'
pattern = r'\b(\d{2,3})\b'
จากตัวอย่างถ้าตีเป็นคำพูดความหมายคือ เลือกตัวเลข 2 ตัว หรือ 3ตัวที่เขียนติดกัน โดยมีการเว้นวรรคด้านหน้าและเว้นวรรคด้านหลัง
แบบประยุกต์ใช้ร่วมกับ Non-Capturing Group
text = " a cat and rat.bat"
regex = re.compile(pattern=r'(?:c|r|b)at')
numbers = regex.findall(text)
print(numbers) #['cat', 'rat', 'bat']
question mark
pattern = r'\d{2}d?'
regex = re.compile(pattern)
numbers = regex.findall(text)
print(numbers) #['44', '550', '404', '70']
จะเห็นว่าให้ผลลัพท์เหมือนตัวอย่างก่อนหน้าเลย'\d{2}d?' คือเจ้าตัว ‘?’ มันมีความหมายประมาณว่า เอาตัวอักษรที่กำหนด1 ตัว แต่จะมีหรือไม่มีตัวอักษรนั้นก็ได้
จากตัวอย่าง จะกำหนด เอาตัวเลข2ตัวจาก \d{2} และกำหนดตัวเลขอีก1ตัว ซึ่งจะมีตัวหรือไม่มีก็ได้ เลยให้ผลลัพท์เท่ากันกับการกำหนด\d{2}|\d{3}
Asterisk
text1 = 'word are abbbc abbbbbc abc ac ca'
regex = re.compile(pattern=r'ab*c')
print(regex.findall(text1)) #['abbbc', 'abbbbbc', 'abc', 'ac']
คล้ายกับquestion mark แต่เป็น0 หรือมากกว่า จากตัวอย่างคือจะมี b กี่ตัวก็ได้ หรือจะไม่มีเลยก็ได้
Plus
text1 = 'word are abbbc abbbbbc abc ac ca'
regex = re.compile(pattern=r'ab+c')
print(regex.findall(text1)) #['abbbc', 'abbbbbc', 'abc']
จะเหมือนAsterisk ต่างกันตรงที่ต้องมีอย่างน้อย1ตัว แต่จะมีมากเท่าไหร่ก็ได้
dot
text1 = 'word are \n abc'
regex = re.compile(pattern=r'a..')
print(regex.findall(text1)) #['are', 'abc']
ใช้กำหนดแทนตัวอักษรตัวไหนก็ได้1ตัว ยกเว้น ขึ้นบรรทัดใหม่ ‘\n’
ถ้าหาก
regex = re.compile(pattern=r'.')
['w', 'o', 'r', 'd', ' ', 'a', 'r', 'e', ' ', 'a', 'b', 'c']
ก็สำหรับเนื้อหาในส่วนของGrouping Patterns และcharacter Patterns ก็หมดเท่านี้ละครับ ถ้าติดปัญหาหรือมีข้อสงสัย ถามมาได้เลยครับ ขอบคุณครับ