JavaRush /Blog Java /Random-VI /Biểu thức chính quy trong Java (RegEx)

Biểu thức chính quy trong Java (RegEx)

Xuất bản trong nhóm
Biểu thức chính quy là một chủ đề mà các lập trình viên, ngay cả những người có kinh nghiệm, thường trì hoãn cho đến sau này. Tuy nhiên, hầu hết các nhà phát triển Java sớm hay muộn sẽ phải đối mặt với việc xử lý văn bản. Thông thường nhất - với các thao tác tìm kiếm trong văn bản và chỉnh sửa. Nếu không có các biểu thức chính quy, mã chương trình nhỏ gọn và hiệu quả liên quan đến xử lý văn bản đơn giản là không thể tưởng tượng được. Vì vậy, đừng trì hoãn nữa, hãy giải quyết vấn đề của những người “chính quy” ngay bây giờ. Đây không phải là một nhiệm vụ khó khăn như vậy.

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:
  1. viết nó dưới dạng một chuỗi bằng cú pháp biểu thức chính quy;
  2. biên dịch chuỗi này thành một biểu thức chính quy;
Làm việc với các biểu thức chính quy trong bất kỳ chương trình Java nào đều bắt đầu bằng việc tạo một đối tượng lớp 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 Patternvà 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 Patternlà một hàm tạo biểu thức chính quy. Bên dưới, phương thức này compilegọ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:
1. Siêu ký tự để khớp ranh giới dòng hoặc văn bản
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
2. Siêu ký tự tìm kiếm lớp ký tự
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
3. Siêu ký tự tìm kiếm ký hiệu soạn thảo văn bản
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
4. Siêu ký tự để nhóm ký tự
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)
5. Siêu ký hiệu để biểu thị số lượng ký tự - lượng từ. Bộ định lượng luôn đứng sau một ký tự hoặc nhóm ký tự.
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:
  1. Trong mẫu đã cho, ký tự đầu tiên là ký tự chữ cái tiếng Nga А. Matcherkhớ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 đó Matchernó đ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.

    Biểu thức chính quy trong Java - 2
  2. Sau khi tìm thấy kết quả khớp với ký tự đầu tiên của mẫu, Matchernó 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.

    Biểu thức chính quy trong Java - 3

    Ở 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".

  3. Matcherchuyể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ên Matchernó 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).

    Biểu thức chính quy trong Java - 4

    Trên thực tế, Matchernó 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ộ.

  4. 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:

    Biểu thức chính quy trong Java - 5
  5. 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: Biểu thức chính quy trong Java - 6

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. Biểu thức chính quy trong Java - 7

Chế độ định lượng lười biếng

  1. 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:

    Biểu thức chính quy trong Java - 8
  2. 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:

    Biểu thức chính quy trong Java - 9
  3. 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. Matchersẽ 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ự “ а” .

    Biểu thức chính quy trong Java - 10
  4. 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 “ “ л), Matchernê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:

    Biểu thức chính quy trong Java - 11
  5. 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.

    Biểu thức chính quy trong Java - 12
Kết quả của phương pháp, mainkhi 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ày Patterncó 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ề flagscá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ố limitxá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ếm limit-1kế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ỏ;
Ví dụ:
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 Matcherbên dưới.

Phương thức lớp đối sánh

Matcherlà 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, Matcherlớ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, StringBuildervà 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: SegmentCharBufferPatternmatcher
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 replaceFirsttạo ra replaceAllmộ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 replaceFirstchỉ thay thế kết quả khớp đầu tiên và replaceAlltấ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 Matchercũ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 PatternMatcherđượ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 PatternMatcher. 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 PatternMatcher.

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ớp Patternvà 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.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION