Biểu thức chính quy RegEx là gì?
Trên thực tế, biểu thức chính quy (RegEx trong Java) là một mẫu để tìm kiếm một chuỗi trong văn bản. Trong Java, biểu diễn ban đầu của mẫu này luôn là một chuỗi, nghĩa là một đối tượng của lớp String. Tuy nhiên, không phải bất kỳ chuỗi nào cũng có thể được biên dịch thành biểu thức chính quy, chỉ những chuỗi tuân thủ các quy tắc viết biểu thức chính quy - cú pháp được xác định trong đặc tả ngôn ngữ. Để viết một biểu thức chính quy, các ký tự chữ cái và số được sử dụng, cũng như các siêu ký tự - các ký tự có ý nghĩa đặc biệt trong cú pháp của biểu thức chính quy. Ví dụ:String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;
Tạo biểu thức chính quy trong Java
Để tạo RegEx trong Java, bạn cần làm theo hai bước đơn giản:- viết nó dưới dạng một chuỗi bằng cú pháp biểu thức chính quy;
- biên dịch chuỗi này thành một biểu thức chính quy;
Pattern
. Để làm điều này, bạn cần gọi một trong hai phương thức tĩnh có sẵn trong lớp compile
. Phương thức đầu tiên nhận một đối số - một chuỗi ký tự của biểu thức chính quy và phương thức thứ hai - cộng với một tham số khác bật chế độ so sánh mẫu với văn bản:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
Danh sách các giá trị tham số có thể có flags
được xác định trong lớp Pattern
và có sẵn cho chúng ta dưới dạng các biến lớp tĩnh. Ví dụ:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//searching for matches with the pattern will be done case-insensitively.
Về cơ bản, lớp này Pattern
là một hàm tạo biểu thức chính quy. Bên dưới, phương thức này compile
gọi hàm tạo riêng của lớp Pattern
để tạo chế độ xem được biên dịch. Phương pháp tạo một phiên bản mẫu này được triển khai với mục tiêu tạo nó như một đối tượng bất biến. Khi tạo, việc kiểm tra cú pháp của biểu thức chính quy sẽ được thực hiện. Nếu có lỗi trong dòng, một ngoại lệ sẽ được tạo ra PatternSyntaxException
.
Cú pháp biểu thức chính quy
Cú pháp biểu thức chính quy dựa trên việc sử dụng các ký hiệu<([{\^-=$!|]})?*+.>
, có thể kết hợp với các ký tự chữ cái. Tùy thuộc vào vai trò của họ, họ có thể được chia thành nhiều nhóm:
Siêu ký tự | Mục đích |
---|---|
^ | đầu dòng |
$ | kết thúc dòng |
\b | Ranh giới từ |
\B | không giới hạn từ |
\MỘT | bắt đầu nhập liệu |
\G | kết thúc trận đấu trước |
\Z | kết thúc đầu vào |
\z | kết thúc đầu vào |
Siêu ký tự | Mục đích |
---|---|
\d | biểu tượng kỹ thuật số |
\D | ký tự không phải số |
\S | ký tự không gian |
\S | ký tự không phải khoảng trắng |
\w | ký tự chữ và số hoặc dấu gạch dưới |
\W | bất kỳ ký tự nào không phải là chữ cái, số hoặc dấu gạch dưới |
. | bất kỳ ký tự nào |
Siêu ký tự | Mục đích |
---|---|
\t | ký tự tab |
\N | ký tự dòng mới |
\r | ký tự trả về vận chuyển |
\f | đi tới trang mới |
\u0085 | ký tự dòng tiếp theo |
\u 2028 | ký tự phân cách dòng |
\u 2029 | ký hiệu phân cách đoạn văn |
Siêu ký tự | Mục đích |
---|---|
[a B C] | bất kỳ điều nào ở trên (a, b hoặc c) |
[^abc] | bất kỳ điều gì khác ngoài những điều được liệt kê (không phải a, b, c) |
[a-zA-Z] | hợp nhất phạm vi (các ký tự Latinh từ a đến z không phân biệt chữ hoa chữ thường) |
[quảng cáo[mp]] | nối các ký tự (a đến d và m đến p) |
[az&&[def]] | giao điểm của các ký hiệu (ký hiệu d,e,f) |
[az&&[^bc]] | trừ ký tự (ký tự a, dz) |
Siêu ký tự | Mục đích |
---|---|
? | một hoặc thiếu |
* | không hoặc nhiều lần |
+ | một hoặc nhiều lần |
{N} | n lần |
{N,} | n lần hoặc hơn |
{n,m} | không ít hơn n lần và không quá m lần |
Chế độ định lượng tham lam
Điểm đặc biệt của lượng từ là khả năng sử dụng chúng ở các chế độ khác nhau: tham lam, siêu tham lam và lười biếng. Chế độ cực kỳ tham lam được bật bằng cách thêm ký hiệu “+
” sau bộ định lượng và chế độ lười biếng bằng cách thêm ký hiệu “ ?
“. Ví dụ:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
Lấy mẫu này làm ví dụ, chúng ta hãy cố gắng hiểu cách hoạt động của bộ định lượng ở các chế độ khác nhau. Theo mặc định, bộ định lượng hoạt động ở chế độ tham lam. Điều này có nghĩa là nó tìm kiếm kết quả khớp dài nhất có thể trong chuỗi. Kết quả của việc chạy mã này:
public static void main(String[] args) {
String text = "Egor Alla Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
chúng ta sẽ nhận được kết quả đầu ra sau: Alla Alexa Thuật toán tìm kiếm cho một mẫu nhất định " А.+а
" được thực thi theo trình tự sau:
-
Trong mẫu đã cho, ký tự đầu tiên là ký tự chữ cái tiếng Nga
А
.Matcher
khớp nó với mọi ký tự của văn bản, bắt đầu từ vị trí 0. Tại vị trí 0 trong văn bản của chúng ta có một ký hiệuЕ
, do đóMatcher
nó đi qua các ký tự trong văn bản một cách tuần tự cho đến khi khớp với mẫu. Trong ví dụ của chúng tôi, đây là biểu tượng ở vị trí số 5. -
Sau khi tìm thấy kết quả khớp với ký tự đầu tiên của mẫu,
Matcher
nó sẽ kiểm tra kết quả khớp với ký tự thứ hai của mẫu. Trong trường hợp của chúng tôi, đây là ký hiệu “.
”, viết tắt của bất kỳ ký tự nào.Ở vị trí thứ sáu là ký hiệu chữ cái
л
. Tất nhiên, nó phù hợp với mẫu "bất kỳ ký tự nào". -
Matcher
chuyển sang kiểm tra ký tự tiếp theo từ mẫu. Trong mẫu của chúng tôi, nó được chỉ định bằng cách sử dụng.+
bộ định lượng “ ”. Vì số lần lặp lại của “ký tự bất kỳ” trong mẫu là một hoặc nhiều lần, nênMatcher
nó lần lượt lấy ký tự tiếp theo từ chuỗi và kiểm tra xem nó có tuân thủ mẫu hay không, miễn là điều kiện “ký tự bất kỳ” được đáp ứng, trong ví dụ của chúng tôi - cho đến cuối dòng ( từ vị trí số 7 - số 18 của văn bản).Trên thực tế,
Matcher
nó nắm bắt toàn bộ câu thoại đến cuối cùng - đây là nơi mà “lòng tham” của nó bộc lộ. -
Sau khi
Matcher
đến cuối văn bản và kiểm tra xong phần “А.+
” của mẫu, Matcher bắt đầu kiểm tra phần còn lại của mẫu - ký tự chữ cáiа
. Vì văn bản theo hướng thuận đã kết thúc nên việc kiểm tra diễn ra theo hướng ngược lại, bắt đầu từ ký tự cuối cùng: -
Matcher
"ghi nhớ" số lần lặp lại trong mẫu ".+
" mà tại đó nó đạt đến cuối văn bản, do đó, nó giảm số lần lặp lại đi một và kiểm tra mẫu cho văn bản cho đến khi tìm thấy kết quả khớp:
Chế độ định lượng cực kỳ tham lam
Ở chế độ siêu tham lam, trình so khớp hoạt động tương tự như cơ chế của chế độ tham lam. Điểm khác biệt là khi bạn kéo văn bản đến cuối dòng thì không có thao tác tìm kiếm ngược. Nghĩa là, ba giai đoạn đầu tiên của chế độ siêu tham lam sẽ tương tự như chế độ tham lam. Sau khi thu thập toàn bộ chuỗi, trình so khớp sẽ thêm phần còn lại của mẫu và so sánh nó với chuỗi đã thu. Trong ví dụ của chúng tôi, khi thực thi phương thức chính với mẫu "А.++а
", sẽ không tìm thấy kết quả khớp nào.
Chế độ định lượng lười biếng
-
Trong chế độ này, ở giai đoạn ban đầu, cũng như ở chế độ tham lam, một kết quả khớp được tìm kiếm với ký tự đầu tiên của mẫu:
-
Tiếp theo, nó tìm kiếm sự trùng khớp với ký tự tiếp theo trong mẫu - bất kỳ ký tự nào:
-
Không giống như chế độ tham lam, chế độ lười tìm kiếm kết quả khớp ngắn nhất trong văn bản, do đó, sau khi tìm thấy kết quả khớp với ký tự thứ hai của mẫu, được chỉ định bằng dấu chấm và khớp với ký tự ở vị trí số 6 của văn bản, nó sẽ tìm kiếm kết quả phù hợp.
Matcher
sẽ kiểm tra xem văn bản có khớp với phần còn lại của mẫu hay không - ký tự “а
” . -
Vì không tìm thấy kết quả khớp với mẫu trong văn bản (ở vị trí số 7 trong văn bản có ký hiệu “ “
л
),Matcher
nên nó thêm một “ký tự bất kỳ” khác trong mẫu, vì nó được chỉ định là một hoặc nhiều lần, và một lần nữa so sánh mẫu với văn bản ở các vị trí từ số 5 đến số 8: -
Trong trường hợp của chúng tôi, một kết quả trùng khớp đã được tìm thấy, nhưng vẫn chưa đến phần cuối của văn bản. Do đó, từ vị trí số 9, việc kiểm tra bắt đầu bằng cách tìm kiếm ký tự đầu tiên của mẫu bằng thuật toán tương tự và sau đó lặp lại cho đến hết văn bản.
main
khi sử dụng А.+?а
mẫu " ", chúng ta sẽ nhận được kết quả sau: Alla Alexa Như có thể thấy từ ví dụ của chúng ta, khi sử dụng các chế độ định lượng khác nhau cho cùng một mẫu, chúng ta đã nhận được các kết quả khác nhau. Vì vậy, cần tính đến tính năng này và chọn chế độ mong muốn tùy thuộc vào kết quả mong muốn trong quá trình tìm kiếm.
Ký tự thoát trong biểu thức chính quy
Vì một biểu thức chính quy trong Java, hay chính xác hơn là biểu diễn ban đầu của nó, được chỉ định bằng cách sử dụng một chuỗi ký tự, nên cần phải tính đến các quy tắc của đặc tả Java liên quan đến các chuỗi ký tự. Cụ thể, ký tự dấu gạch chéo ngược "\
" trong chuỗi ký tự trong mã nguồn Java được hiểu là ký tự thoát để cảnh báo trình biên dịch rằng ký tự theo sau nó là ký tự đặc biệt và phải được hiểu theo cách đặc biệt. Ví dụ:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
Do đó, trong các chuỗi ký tự mô tả một biểu thức chính quy và sử dụng \
ký tự " " (ví dụ: đối với siêu ký tự), nó phải được nhân đôi để trình biên dịch mã byte Java không diễn giải nó theo cách khác. Ví dụ:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
Ký tự dấu gạch chéo ngược kép cũng nên được sử dụng để thoát khỏi các ký tự đặc biệt nếu chúng ta dự định sử dụng chúng làm ký tự "thông thường". Ví dụ:
String regex = "How\\?"; // template for searching the string "How?"
Các phương thức của lớp Pattern
Lớp nàyPattern
có các phương thức khác để làm việc với các biểu thức chính quy: String pattern()
– trả về biểu diễn chuỗi gốc của biểu thức chính quy mà đối tượng được tạo từ đó Pattern
:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)
– cho phép bạn kiểm tra biểu thức chính quy được truyền trong tham số biểu thức chính quy so với văn bản được truyền trong tham số input
. Trả về: true – nếu văn bản khớp với mẫu; sai – ngược lại; Ví dụ:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla Alexander"));//false
int flags()
– trả về flags
các giá trị tham số mẫu đã được đặt khi nó được tạo hoặc 0 nếu tham số này không được đặt. Ví dụ:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)
– chia văn bản được truyền dưới dạng tham số thành một mảng gồm các phần tử String
. Tham số limit
xác định số lượng kết quả phù hợp tối đa được tìm kiếm trong văn bản:
- khi
limit>0
– tìm kiếmlimit-1
kết quả phù hợp được thực hiện; - at
limit<0
– tìm kiếm tất cả kết quả phù hợp trong văn bản - khi
limit=0
– tìm kiếm tất cả các kết quả khớp trong văn bản, trong khi các dòng trống ở cuối mảng bị loại bỏ;
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("\\s");
String[] strings = pattern.split(text,2);
for (String s : strings) {
System.out.println(s);
}
System.out.println("---------");
String[] strings1 = pattern.split(text);
for (String s : strings1) {
System.out.println(s);
}
}
Đầu ra của bảng điều khiển: Egor Alla Anna -------- Egor Alla Anna Chúng ta sẽ xem xét một phương thức lớp khác để tạo một đối tượng Matcher
bên dưới.
Phương thức lớp đối sánh
Matcher
là một lớp mà từ đó một đối tượng được tạo ra để tìm kiếm các mẫu. Matcher
– đây là một “công cụ tìm kiếm”, một “công cụ” của các biểu thức chính quy. Để tìm kiếm, anh ta cần được cung cấp hai thứ: kiểu tìm kiếm và “địa chỉ” để tìm kiếm. Để tạo một đối tượng, Matcher
lớp này cung cấp phương thức sau Pattern
: рublic Matcher matcher(CharSequence input)
Là một đối số, phương thức này lấy một chuỗi các ký tự trong đó việc tìm kiếm sẽ được thực hiện. Đây là những đối tượng của các lớp thực hiện giao diện CharSequence
. Bạn có thể truyền không chỉ String
, mà còn cả StringBuffer
, StringBuilder
và làm đối số . Mẫu tìm kiếm là đối tượng lớp mà phương thức này được gọi . Ví dụ về việc tạo một trình so khớp: Segment
CharBuffer
Pattern
matcher
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using the pattern "a*b"
Giờ đây, với sự trợ giúp của “công cụ tìm kiếm”, chúng ta có thể tìm kiếm các kết quả phù hợp, tìm ra vị trí của kết quả phù hợp trong văn bản và thay thế văn bản bằng các phương thức lớp. Phương thức boolean find()
tìm kiếm kết quả khớp tiếp theo trong văn bản có mẫu. Sử dụng phương pháp này và toán tử vòng lặp, bạn có thể phân tích toàn bộ văn bản theo mô hình sự kiện (thực hiện các thao tác cần thiết khi xảy ra sự kiện - tìm sự trùng khớp trong văn bản). Ví dụ: bằng cách sử dụng các phương thức của lớp này, int start()
bạn int end()
có thể xác định vị trí của kết quả khớp trong văn bản và sử dụng các phương thức này String replaceFirst(String replacement)
để String replaceAll(String replacement)
thay thế các kết quả khớp trong văn bản bằng một văn bản thay thế khác. Ví dụ:
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found" + text.substring(start,end) + " с "+ start + " By " + (end-1) + "position");
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Olga"));
System.out.println(text);
}
Đầu ra chương trình: Đã tìm thấy một kết quả trùng khớp Alla từ 5 đến 8 vị trí Một kết quả phù hợp đã được tìm thấy Anna từ 10 đến 13 vị trí Egor Ira Anna Egor Olga Olga Egor Alla Anna Từ ví dụ này, rõ ràng là các phương thức replaceFirst
tạo ra replaceAll
một đối tượng mới String
- một chuỗi, trong đó là văn bản nguồn trong đó các kết quả khớp với mẫu được thay thế bằng văn bản được truyền vào phương thức làm đối số. Hơn nữa, phương pháp này replaceFirst
chỉ thay thế kết quả khớp đầu tiên và replaceAll
tất cả các kết quả khớp trong thử nghiệm. Văn bản gốc vẫn không thay đổi. Việc sử dụng các phương thức lớp khác Matcher
cũng như các ví dụ về biểu thức chính quy có thể được tìm thấy trong loạt bài viết này . Các thao tác phổ biến nhất với biểu thức chính quy khi làm việc với văn bản là từ các lớp Pattern
và Matcher
được tích hợp vào String
. Đây là những phương pháp như split
, matches
, replaceFirst
, replaceAll
. Nhưng trên thực tế, "dưới mui xe" họ sử dụng Pattern
và Matcher
. Do đó, nếu bạn cần thay thế văn bản hoặc so sánh các chuỗi trong chương trình mà không cần viết mã không cần thiết, hãy sử dụng các phương thức của tệp String
. Nếu bạn cần các khả năng nâng cao, hãy nghĩ đến các lớp Pattern
và Matcher
.
Phần kết luận
Một biểu thức chính quy được mô tả trong chương trình Java bằng cách sử dụng các chuỗi khớp với mẫu được xác định bởi các quy tắc. Khi mã chạy, Java sẽ biên dịch lại chuỗi này thành một đối tượng lớpPattern
và sử dụng đối tượng lớp Matcher
để tìm kết quả khớp trong văn bản. Như tôi đã nói lúc đầu, các biểu thức chính quy thường được dành cho phần sau, được coi là một chủ đề khó. Tuy nhiên, nếu bạn hiểu những điều cơ bản về cú pháp, siêu ký tự, lối thoát và nghiên cứu các ví dụ về biểu thức chính quy, chúng sẽ trở nên đơn giản hơn nhiều so với cái nhìn đầu tiên.
GO TO FULL VERSION