Chương tiếp theo của bài học nâng cao Python, chúng ta sẽ cùng tìm hiểu về Regular Expression (RegEx) với module re
cùng các ví dụ cụ thể để bạn dễ hình dung và nắm bắt kĩ hơn kiến thức về RegEx. Cùng theo dõi nhé!
Regular Expression (RegEx) hay còn gọi là Biểu thức chính quy là một đoạn các ký tự đặc biệt theo những khuôn mẫu (pattern) nhất định, đại diện cho chuỗi hoặc một tập các chuỗi. Ví dụ:
^a...s$
Đoạn code trên xác định quy tắc RegEx: bất kỳ chuỗi nào có năm chữ cái, bắt đầu bằng a
và kết thúc bằng s
.
Biểu thức | Chuỗi ví dụ | Mô tả |
^a...s$ | abs | Không phù hợp vì chỉ có 3 ký tự |
alias | Phù hợp | |
abyss | Phù hợp | |
Alias | Không phù hợp vì chữ cái đầu viết hoa A | |
An abacus | Không phù hợp vì chữ cái đầu viết hoa A và nhiều hơn 5 ký tự |
Regular Expression trong Python được thể hiện qua module re
, nên việc đầu tiên khi các bạn muốn sử dụng Regular Expression thì cần phải import module re
vào chương trình. Thử với ví dụ trên:
import re
pattern = '^a...s$'
test_string = 'abyss'
result = re.match(pattern, test_string)
if result:
print("Tim kiem thanh cong.")
else:
print("Tim kiem khong thanh cong.")
Ở đây chúng ta vừa sử dụng hàm re.match()
để tìm kiếm test_string
tương ứng với pattern
. Phương thức trả về đối tượng tương ứng nếu tìm kiếm thành công, trả về None
nếu không tìm thấy.
Hầu như ngôn ngữ nào cũng hỗ trợ Regular Expression, kể đến như JavaScript, C#, Java, PHP, Ruby, SQL, Oracle, Perl… nhưng được sử dụng phổ biến nhất trong Unix/Linux.
Còn một số hàm khác có trong mudule re
để hoạt động với RegEx. Trước khi đi sâu vào các hàm này, hãy tìm hiểu kĩ hơn về biểu thức chính quy RegEx.
Cú pháp pattern sử dụng trong RegEx Python
Pattern ta hiểu là một đối tượng mẫu, một phiên bản đã được biên dịch của một biểu thức chính quy. Để chỉ định biểu thức chính quy, ta sử dụng các ký tự đặc biệt, bao gồm:
[] . ^ $ * + ? {} () \ |
Trong ví dụ trên là ký tự ^
và $
.
Dấu ngoặc vuông []
Dấu ngoặc vuông sử dụng để thể hiện tập các ký tự bạn muốn khớp.
Biểu thức | Chuỗi ví dụ | Mô tả |
[abc] | a | Khớp với ký tự a |
ac | Khớp với ký tự a hoặc c | |
Hey Jude | Không khớp |
Ở đây, [abc]
sẽ khớp nếu chuỗi bạn truyền có chứa bất kỳ ký tự a
, b
hoặc c
nào.
Bạn cũng có thể chỉ định một phạm vi các ký tự bằng cách sử dụng -
bên trong dấu ngoặc vuông.
[a-e]
tương tự với[abcde]
.[1-4]
tương tự với[1234]
.[0-39]
tương tự với[01239]
.
Nếu ký tự đầu tiên của tập hợp là ^
thì tất cả các ký tự không được định nghĩa trong tập hợp sẽ được so khớp.
[^abc]
nghĩa là khớp với các chuỗi không có ký tựa
,b
hayc
.[^0-9
] nghĩa là khớp với các chuỗi không có ký tự chữ số nào.
Các ký tự đặc biệt trong []
sẽ được coi như ký tự thông thường.
[(+)]
khớp với bất kỳ chuỗi nào có ký tự(
,+
hoặc)
.
Dấu chấm .
Dấu chấm khớp với bất kỳ ký tự đơn thông thường nào ngoại trừ ký tự tạo dòng mới '\n'
.
Biểu thức | Chuỗi ví dụ | Mô tả |
.. | a | Không khớp vì chỉ có một ký tự |
ac | Khớp vì có hai ký tự | |
acd | Khớp vì có hai ký tự trở lên |
Dấu mũ ^
Biểu tượng dấu mũ ^
được sử dụng để khớp ký tự đứng đầu một chuỗi.
Biểu thức | Chuỗi ví dụ | Mô tả |
^a | a | Khớp vì bắt đầu bằng a |
abc | Khớp vì bắt đầu bằng a | |
bac | Không khớp vì a không nằm ở đầu tiên | |
^ab | abc | Khớp vì bắt đầu bằng ab |
acb | Không khớp, bắt đầu bằng a nhưng ký tự tiếp theo không phải b |
Biểu tượng Dollar $
Biểu tượng Dollar $
được sử dụng để khớp ký tự kết thúc một chuỗi.
Biểu thức | Chuỗi ví dụ | Mô tả |
a$ | a | Khớp vì kết thúc bằng a |
formula | Khớp vì kết thúc bằng a | |
cab | Không khớp vì a không nằm ở vị trí cuối cùng |
Dấu hoa thị *
Biểu tượng dấu hoa thị *
có thể khớp với chuỗi có hoặc không có ký tự được định nghĩa trước nó. Ký tự này có thể được lặp lại nhiều lần mà không bị giới hạn số lượng.
Biểu thức | Chuỗi ví dụ | Mô tả |
ma*n | mn | Khớp vì ký tự trước * có thể không xuất hiện |
man | Khớp vì có xuất hiện đầy đủ các ký tự | |
maaaan | Khớp vì ký tự trước * có thể xuất hiện nhiều lần | |
main | Không khớp vì không giống pattern, n không nằm kế a | |
woman | Khớp vì có xuất hiện đầy đủ các ký tự |
Dấu cộng +
Biểu tượng dấu cộng +
có thể khớp với chuỗi có một hoặc nhiều ký tự được định nghĩa trước nó. Ký tự này có thể được lặp lại nhiều lần mà không bị giới hạn số lượng.
Biểu thức | Chuỗi ví dụ | Mô tả |
ma+n | mn | Không khớp vì ký tự a trước + không xuất hiện |
man | Khớp vì có xuất hiện đầy đủ các ký tự | |
maaaan | Khớp vì ký tự trước + có thể xuất hiện nhiều lần | |
main | Không khớp vì không giống pattern, n không nằm kế a | |
woman | Khớp vì có xuất hiện đầy đủ các ký tự |
Dấu chấm hỏi ?
Biểu tượng dấu chấm hỏi có thể khớp với chuỗi có hoặc không có ký tự được định nghĩa trước nó. Ký tự này không thể được lặp lại nhiều lần, chỉ giới hạn số lượng với một lần xuất hiện.
Biểu thức | Chuỗi ví dụ | Mô tả |
ma?n | mn | Khớp vì ký tự trước ? có thể không xuất hiện |
man | Khớp vì có xuất hiện đầy đủ các ký tự | |
maaaan | Không khớp vì ký tự trước ? chỉ có thể xuất hiện 1 lần | |
main | Không khớp vì không giống pattern, n không nằm kế a | |
woman | Khớp vì có xuất hiện đầy đủ các ký tự |
Dấu ngoặc nhọn {}
Dấu ngoặc nhọn sử dụng theo công thức tổng quát: {n,m}
, đại diện cho việc ký tự đằng trước nó có thể xuất hiện tối thiểu n lần vào tối đa m lần. n
và m
là số nguyên dương và n <= m.
- Nếu bỏ trống
n
, giá trị này mặc định bằng 0. - Nếu bỏ trống
m
, giá trị này mặc định là vô hạn.
Biểu thức | Chuỗi ví dụ | Mô tả |
a{2,3} | abc dat | Không khớp vì không thỏa mãn điều kiện |
abc daat | Khớp vì có xuất hiện 2 ký tự a (daat ) | |
aabc daaat | Khớp vì có xuất hiện 2 và 3 ký tự a (aabc và daaat ) | |
aabc daaaat | Khớp vì có xuất hiện 2 và 3 ký tự a (aabc và daaaat ) |
Hãy thử một ví dụ nữa: RegEx [0-9] {2, 4}
này khớp với chuỗi có tối thiểu 2 chữ số và tối đa không quá 4 chữ số.
Biểu thức | Chuỗi ví dụ | Mô tả |
[0-9]{2,4} | ab123csde | Khớp vì thỏa mãn điều kiện: ab123csde |
12 and 345673 | Khớp vì thỏa mãn điều kiện: 12 và 345673 | |
1 and 2 | Không khớp vì chuỗi chỉ có 1 chữ số |
Dấu sổ dọc |
Biểu tượng dấu sổ dọc |
này có thể khớp với chuỗi tồn tại 1 trong 2 ký tự được định nghĩa trước và sau nó.
Biểu thức | Chuỗi ví dụ | Mô tả |
a|b | cde | Không khớp vì a , b đều không xuất hiện |
ade | Khớp vì thỏa mãn điều kiện, có a xuất hiện: ade | |
acdbea | Khớp vì thỏa mãn điều kiện, a và b đều xuất hiện: acdbea |
Ở đây, a|b
khớp với bất kỳ chuỗi nào chứa a
hoặc b
.
Dấu ngoặc đơn ()
Dấu ngoặc đơn ()
được sử dụng để gom nhóm các pattern lại với nhau, chuỗi sẽ khớp với biểu thức chính quy bên trong dấu ngoặc này.
Ví dụ: (a|b|c)xz
khớp với bất kỳ chuỗi nào có a
hoặc b
hoặc c
đứng trước xz
.
Biểu thức | Chuỗi ví dụ | Mô tả |
(a|b|c)xz | ab xz | Không khớp vì a hay b có đứng trước nhưng không liền với xz |
abxz | Khớp vì thỏa mãn điều kiện, có b xuất hiện sát trước xz : abxz | |
axz cabxz | Khớp vì thỏa mãn điều kiện, cả a và b đều xuất hiện sát trước xz : axz cabxz |
Dấu gạch chéo ngược \
Dấu gạch chéo ngược được sử dụng để thoát các ký tự đặc biệt, nghĩa là khi đứng trước một kí tự đặc biệt, \
sẽ biến kí tự này thành một kí tự thường, bạn có thể tìm kiếm kí tự đặc biệt này trong chuỗi như các kí tự thường khác.
Ví dụ: \$a
sẽ khớp với chuỗi chứa ký tự $
đứng trước a
. Ở đây, biểu tượng Dollar $
không sử dụng để khớp một chuỗi kết thúc bằng ký tự đi cùng nó như trong công cụ RegEx, $
chỉ là ký tự bình thường.
Tuy nhiên, một dấu gạch chéo ngược cũng sẽ biến một kí tự thường liền kế phía sau thành một kí tự đặc biệt.
Ví dụ, trường hợp ký tự b
không có dấu gạch chéo ngược sẽ khớp với các ký tự b
in thường, nhưng khi nó có thêm dấu gạch chéo ngược, \b
thì nó trở thành kí tự đặc biệt, không khớp với bất kì ký tự nào nữa.
Một số pattern đi với \
1. \A
– Khớp với các ký tự theo sau nó nằm ở đầu chuỗi.
Biểu thức | Chuỗi ví dụ | Mô tả |
\Athe | the sun | Khớp vì the nằm ở đầu chuỗi |
In the sun | Không khớp vì the không nằm ở đầu chuỗi |
2. \b
– Khớp với các ký tự được chỉ định nằm ở đầu hoặc cuối của từ.
Biểu thức | Chuỗi ví dụ | Mô tả |
\bfoo | football | Khớp vì thỏa mãn điều kiện, foo nằm ở đầu chuỗi |
a football | Khớp vì thỏa mãn điều kiện, foo nằm ở đầu từ thứ 2 trong chuỗi | |
afootball | Không khớp vì foo nằm ở giữa từ trong chuỗi. | |
foo\b | the foo | Khớp vì thỏa mãn điều kiện, foo nằm ở cuối chuỗi |
the afoo test | Khớp vì thỏa mãn điều kiện, foo nằm ở cuối từ thứ 2 trong chuỗi | |
the afootest | Không khớp vì foo nằm ở giữa từ trong chuỗi. |
3. \B
– Trái ngược với \b
, khớp với các ký tự được chỉ định không nằm ở đầu hoặc cuối của từ.
Biểu thức | Chuỗi ví dụ | Mô tả |
\bfoo | football | Không khớp vì foo nằm ở đầu chuỗi |
a football | Không khớp vì foo nằm ở đầu từ thứ 2 trong chuỗi | |
afootball | Khớp vì foo nằm ở giữa từ trong chuỗi. | |
foo\b | the foo | Không khớp vì foo nằm ở cuối chuỗi |
the afoo test | Không khớp vì foo nằm ở cuối từ thứ 2 trong chuỗi | |
the afootest | Khớp vì foo nằm ở giữa từ trong chuỗi. |
4. \d
– Khớp với các ký tự là chữ số, tương đương với [0-9]
.
Biểu thức | Chuỗi ví dụ | Mô tả |
\d | 12abc3 | Khớp vì thỏa mãn điều kiện: 12abc3 |
Python | Không khớp vì không có số nguyên nào xuất hiện |
5. \D
– Khớp với các ký tự không phải số, tương đương với [^0-9]
.
Biểu thức | Chuỗi ví dụ | Mô tả |
\D | 1ab34"50 | Khớp vì thỏa mãn điều kiện: 1ab34"50 |
1345 | Không khớp vì chuỗi toàn số nguyên xuất hiện |
6. \s
– Khớp với bất kỳ ký tự khoảng trắng nào, tương đương với [ \t\n\r\f\v]
.
Biểu thức | Chuỗi ví dụ | Mô tả |
\s | Python RegEx | Khớp vì chuỗi có khoảng trắng |
PythonRegEx | Không khớp vì chuỗi không có khoảng trắng |
7. \S
– Khớp với bất kỳ ký tự nào không phải khoảng trắng, tương đương với [^ \t\n\r\f\v]
.
Biểu thức | Chuỗi ví dụ | Mô tả |
\S | a b | Khớp vì chuỗi có ký tự a b |
| Không khớp vì chuỗi toàn bộ là khoảng trắng |
8. \w
– Khớp với bất kỳ ký tự chữ cái và chữ số nào, tương đương với [a-zA-Z0-9_]
.
Lưu ý: Dấu gạch dưới _
cũng được coi là một ký tự chữ cái và chữ số.
Biểu thức | Chuỗi ví dụ | Mô tả |
\w | 12&": ;c | Khớp vì chuỗi có ký tự chữ và số 12&": ;c |
%"> ! | Không khớp vì chuỗi không có ký tự chữ và số |
9. \W
– Khớp với bất kỳ ký tự nào không phải là chữ cái và chữ số, tương đương với [^a-zA-Z0-9_]
.
Biểu thức | Chuỗi ví dụ | Mô tả |
\w | 1a2%c | Khớp vì chuỗi có ký tự không phải chữ và số 1a2%c |
Python | Không khớp vì chuỗi chỉ có ký tự chữ cái |
Lưu ý: Dấu gạch dưới _
cũng được coi là một ký tự chữ cái và chữ số.
Tips: Để xây dựng các biểu thức chính quy RegEx, bạn có thể sử dụng công cụ kiểm tra RegEx như regex101
. Công cụ này không chỉ tạo các biểu thức chính quy mà còn giúp bạn tìm hiểu nó kỹ hơn.
Bây giờ thì bạn đã hiểu những điều cơ bản về RegEx, hãy cùng thảo luận về cách sử dụng RegEx trong code Python.
Regular Expression trong Python
Regular Expression trong Python được thể hiện qua module re
, nên việc đầu tiên khi các bạn muốn sử dụng regular expression thì cần phải import module re
vào chương trình.
import re
Module này có rất nhiều các phương thức, hàm và hằng để làm việc với RegEx. Quantrimang.com sẽ liệt kê một số hay được sử dụng kèm theo ví dụ để bạn dễ hình dung và nắm bắt.
re.findall()
Phương thức re.findall() trả về một danh sách các chuỗi chứa tất cả các kết quả khớp với pattern đưa ra.
findall(partern, string)
Trong đó:
pattern
là RegEx.string
là chuỗi cần so khớp.
Ví dụ: Trích xuất các số từ chuỗi cho trước sau: “hello 12 hi 89. Howdy 34”
import re
string = 'hello 12 hi 89. Howdy 34'
pattern = '\d+'
result = re.findall(pattern, string)
print(result)
['12', '89', '34']
re.split()
Phương thức re.split() dùng biểu thức chính quy để ngắt chuỗi thành các chuỗi con và trả về danh sách các chuỗi con này.
re.split(pattern, string, maxsplit)
Trong đó:
pattern
là RegEx.string
là chuỗi cần so khớp.maxsplit
(số nguyên) là số chuỗi tối đa sẽ được ngắt. Nếu để trống thì Python sẽ so khớp và cắt tất cả các chuỗi đạt điều kiện.
Ví dụ: Ngắt tại vị trí có ký tự khoảng trắng:
import re
string = 'The rain in Vietnam.'
pattern = '\s'
result = re.split(pattern, string)
print(result)
['The', 'rain', 'in', 'Vietnam.']
Ví dụ: Ngắt chuỗi ở ký tự khoảng trắng đầu tiên:
import re
string = 'The rain in Vietnam.'
pattern = '\s'
result = re.split(pattern, string, 1)
print(result)
['The', 'rain in Vietnam.']
Nếu không tìm thấy pattern, re.split() trả về danh sách chứa chuỗi rỗng.
re.sub()
Đây là một trong những phương thức quan trọng nhất sử dụng với Regular Expression
Re.sub() sẽ thay thế tất cả các kết quả khớp với pattern trong chuỗi bằng một nội dung khác được truyền vào và trả về chuỗi đã được sửa đổi.
re.sub(pattern, replace, string, count)
Trong đó:
pattern
là RegEx.replace
là nội dung thay thế cho chuỗi kết quả khớp vớipattern
.string
là chuỗi cần so khớp.count
(số nguyên) là số lần thay thế. Nếu để trống thì Python sẽ coi giá trị này bằng 0, so khớp và thay thế tất cả các chuỗi đạt điều kiện.
Ví dụ: Code chương trình xóa tất cả các khoảng trắng
import re
# chuỗi nhiều dòng
string = 'abc 12\
de 23 \n f45 6'
# so khớp các ký tự khoảng trắng
pattern = '\s+'
# chuỗi rỗng
replace = ''
new_string = re.sub(pattern, replace, string)
print(new_string)
abc12de23f456
Nếu không tìm thấy kết quả phù hợp với pattern, re.sub()
sẽ trả về chuỗi rỗng.
Ví dụ: Code chương trình xóa 2 khoảng trắng đầu tiên
import re
# chuỗi nhiều dòng
string = 'abc 12\
de 23 \n f45 6 \n quantrimang website'
# so khớp các ký tự khoảng trắng
pattern = '\s+'
replace = ''
new_string = re.sub(r'\s+', replace, string, 2)
print(new_string)
abc12de23
f45 6
quantrimang website
re.subn()
Phương thức re.subn() sử dụng tương tự như re.sub()
ở trên, nhưng kết quả trả về bao gồm một tuple chứa hai giá trị: chuỗi mới sau khi được thay thế và số lần thay thế đã thực hiện.
import re
# chuỗi nhiều dòng
string = 'abc 12\
de 23 \n f45 6 \n quantrimang website'
# so khớp các ký tự khoảng trắng
pattern = '\s+'
# chuỗi rỗng
replace = ''
new_string = re.subn(pattern, replace, string)
print(new_string)
('abc12de23f456quantrimangwebsite', 6)
re.search()
Phương thức re.search() sử dụng để tìm kiếm chuỗi phù hợp với pattern RegEx. Nếu tìm kiếm thành công, re.search() trả về đối tượng khớp, nếu không, nó trả về None
.
search(pattern, string)
Trong đó:
pattern
là RegEx.string
là chuỗi cần so khớp.
import re
string = "Quantrimang.com la website ban co the hoc Python"
# Kiem tra xem 'Quantrimang' co nam o dau chuoi khong
match = re.search('\AQuantrimang', string)
if match: # nếu tồn tại chuỗi khớp
print("Tim thay 'Quantrimang' nam o dau chuoi") # in ra thong bao nay
else:
print("'Quantrimang' khong nam o dau chuoi") # khong thi in ra thong bao nay
Tim thay 'Quantrimang' nam o dau chuoi
Ở ví dụ này, match
chứa đối tượng phù hợp khớp với pattern.
Đối tượng match
Một số phương thức và thuộc tính thường được sử dụng với đối tượng match.
match.group()
Phương thức group() trả về những phần của chuỗi khớp với pattern.
import re
string = '39801 356, 2102 1111'
pattern = '(\d{3}) (\d{2})'
match = re.search(pattern, string)
if match: #nếu tồn tại chuỗi khớp
print(match.group()) # in ra kết quả
else:
print("Không khớp") # Không thì hiện thông báo
# Output: 801 35
Ở đây, biến match
chứa đối tượng match.
Ta có pattern là (\d{3}) (\d{2})
chia làm hai nhóm nhỏ (\d{3})
và (\d{2})
. Bạn có thể nhận được một phần của chuỗi tương ứng với các nhóm con trong ngoặc đơn này như sau:
>>> match.group(1)
'801'
>>> match.group(2)
'35'
>>> match.group(1, 2)
('801', '35')
>>> match.groups()
('801', '35')
match.start(), match.end() và match.span()
Hàm start() trả về chỉ mục bắt đầu của chuỗi con phù hợp. Tương tự, end() trả về chỉ mục kết thúc của chuỗi con phù hợp.
>>> match.start()
2
>>> match.end()
8
Hàm span() trả về tuple chứa chỉ mục bắt đầu và kết thúc của phần chuỗi phù hợp.
>>> match.span()
(2, 8)
match.re và match.string
Thuộc tính re
của đối tượng match sẽ trả về một biểu thức chính quy. Tương tự, thuộc tính string trả về chuỗi đã được truyền trong đoạn code.
>>> match.re
re.compile('(\\d{3}) (\\d{2})')
>>> match.string
'39801 356, 2102 1111'
Trên đây là tất cả các phương thức thường được sử dụng nhất trong module re.
Sử dụng tiền tố r trước RegEx
Khi tiền tố r
hoặc R
được sử dụng trước một biểu thức chính quy đại diện cho việc chuỗi tiếp sau nó chỉ là những ký tự bình thường.
Ví dụ: '\n'
là một dòng mới newline, còn r'\n'
có nghĩa là chuỗi bao gồm hai ký tự: dấu gạch chéo ngược \
và n
.
Dấu gạch chéo ngược \
được sử dụng để thoát các ký tự như đã nói ở trên. Tuy nhiên, sử dụng tiền tố r
trước \
thì nó chỉ là một ký tự bình thường.
import re
string = '\n and \r are escape sequences.'
result = re.findall(r'[\n\r]', string)
print(result)
# Output: ['\n', '\r']