Đơn giản hóa các tác vụ lập trình phổ biến với API Regex
Trong Phần 1 và 2 của bài viết này, bạn đã được giới thiệu về biểu thức chính quy và API Regex. Bạn đã tìm hiểu về lớp nàyPattern
và xem qua các ví dụ minh họa cấu trúc biểu thức chính quy, từ so khớp mẫu đơn giản bằng cách sử dụng chuỗi ký tự đến so khớp phức tạp hơn bằng cách sử dụng phạm vi, bộ so khớp ranh giới và bộ định lượng. Trong phần này và các phần tiếp theo , chúng ta sẽ xem xét các vấn đề chưa được đề cập trong phần đầu tiên, chúng ta sẽ nghiên cứu các phương thức tương ứng của các lớp Pattern
và Matcher
. PatternSyntaxException
Bạn cũng sẽ tìm hiểu hai tiện ích sử dụng biểu thức chính quy để giải quyết các vấn đề lập trình thông thường dễ dàng hơn. Cái đầu tiên trích xuất các nhận xét từ mã cho tài liệu. Thứ hai là một thư viện mã có thể tái sử dụng được thiết kế để thực hiện phân tích từ vựng - một thành phần thiết yếu của trình biên dịch, trình biên dịch và phần mềm tương tự.
MÃ NGUỒN TẢI XUỐNG
Bạn có thể lấy tất cả mã nguồn (được tạo bởi Jeff Friesen cho JavaWorld) cho các ứng dụng demo trong bài viết này từ đây .Tìm hiểu API Regex
Pattern
và Matcher
là PatternSyntaxException
ba lớp tạo nên API Regex. Mỗi trong số chúng đều cung cấp các phương thức cho phép bạn sử dụng các biểu thức chính quy trong mã của mình.
Các phương thức của lớp Pattern
Một thể hiện của một lớpPattern
là một biểu thức chính quy được biên dịch, còn được gọi là mẫu. Biểu thức chính quy được biên soạn để cải thiện hiệu suất của các hoạt động khớp mẫu. Các phương thức tĩnh sau đây hỗ trợ biên dịch.
Pattern compile(String regex)
biên dịch nội dungregex
thành một biểu diễn trung gian được lưu trữ trong một tệpPattern
. Phương thức này trả về một tham chiếu đến một đối tượng nếu thành công hoặc đưa ra một ngoại lệPatternSyntaxException
nếu phát hiện cú pháp biểu thức chính quy không hợp lệ. Bất kỳ đối tượng nào của lớpMatcher
được sử dụngPattern
hoặc trả về từ đối tượng này đều sử dụng các cài đặt mặc định của nó, chẳng hạn như tìm kiếm phân biệt chữ hoa chữ thường. Ví dụ: đoạn mãPattern p = Pattern.compile("(?m)^\\.");
tạo một đối tượng lưu trữPattern
biểu diễn được biên dịch của biểu thức chính quy để khớp với các chuỗi bắt đầu bằng ký tự dấu chấm.Pattern compile(String regex, int flags)
giải quyết vấn đề tương tự nhưPattern compile(String regex)
, nhưng có tính đếnflags
: một tập hợp các hằng số bit cho cờ bit thuộc loại OR. Lớp nàyPattern
khai báo các hằng sốCANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINES
có thể được kết hợp bằng cách sử dụng bitwise OR (ví dụ:CASE_INSENSITIVE | DOTALL
) và được truyền dưới dạng đối sốflags
.
Ngoại trừ
CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASS
, các hằng số này là một thay thế cho các biểu thức cờ lồng nhau được trình bày trong Phần 1. Nếu gặp một hằng cờ khác với hằng số được xác định trong lớp Pattern
, phương thức Pattern compile(String regex, int flags)
sẽ đưa ra một ngoại lệ java.lang.IllegalArgumentException
. Ví dụ, Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);
tương đương với ví dụ trước, với hằng số Pattern.MULTILINE
và biểu thức cờ lồng nhau (?m)
thực hiện điều tương tự.
Pattern
, cùng với các cờ mà nó sử dụng. Để làm điều này, bạn có thể gọi các phương thức sau:
String pattern()
trả về chuỗi biểu thức chính quy ban đầu được biên dịch thành tệpPattern
.int flags()
trả về cờ của đối tượngPattern
.
Pattern
, nó thường được sử dụng để lấy đối tượng Matcher
để thực hiện các thao tác khớp mẫu. Phương thức này Matcher matcher(Charsequence input)
tạo một đối tượng Matcher
tìm kiếm văn bản input
phù hợp với mẫu đối tượng Pattern
. Khi được gọi, nó trả về một tham chiếu đến đối tượng này Matcher
. Ví dụ: lệnh Matcher m = p.matcher(args[1]);
trả về Matcher
đối tượng Pattern
được tham chiếu bởi biến p
.
Tìm kiếm một lần |
---|
Phương thức static boolean matches(String regex, CharSequence input) lớp Pattern cho phép bạn tiết kiệm việc tạo đối tượng Pattern và Matcher tìm kiếm một lần bằng cách sử dụng mẫu. Phương thức này trả về true nếu input mẫu phù hợp regex , nếu không nó sẽ trả về false. Nếu biểu thức chính quy có lỗi cú pháp thì phương thức sẽ đưa ra một ngoại lệ PatternSyntaxException . Ví dụ: System.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only")); in true , xác nhận rằng cụm từ all lowercase letters and whitespace only chỉ chứa dấu cách và ký tự chữ thường. |
Tách văn bản
Hầu hết các nhà phát triển đều ít nhất một lần viết mã để chia văn bản đầu vào thành các phần cấu thành của nó, chẳng hạn như chuyển đổi tài khoản nhân viên dựa trên văn bản thành một tập hợp các trường. Lớp nàyPattern
cung cấp khả năng giải quyết công việc tẻ nhạt này một cách thuận tiện hơn bằng cách sử dụng hai phương pháp tách văn bản:
-
Phương thức này
String[] split(CharSequence text, int limit)
phân chiatext
theo các kết quả khớp được tìm thấy với mẫu đối tượngPattern
và trả về kết quả trong một mảng. Mỗi phần tử mảng chỉ định một chuỗi văn bản được phân tách khỏi chuỗi tiếp theo bằng một đoạn văn bản khớp mẫu (hoặc cuối văn bản). Các phần tử của mảng có cùng thứ tự xuất hiện trongtext
.Trong phương pháp này, số lượng phần tử mảng phụ thuộc vào tham số
limit
, tham số này cũng kiểm soát số lượng kết quả khớp được tìm thấy.- Giá trị dương tìm kiếm không quá
limit-1
kết quả trùng khớp và độ dài của mảng không quálimit
phần tử. - Nếu giá trị âm, tất cả các kết quả khớp có thể sẽ được tìm kiếm và độ dài của mảng có thể tùy ý.
- Nếu giá trị bằng 0, tất cả các kết quả khớp có thể sẽ được tìm kiếm, độ dài của mảng có thể tùy ý và các dòng trống ở cuối sẽ bị loại bỏ.
- Giá trị dương tìm kiếm không quá
- Phương thức này
String[] split(CharSequence text)
gọi phương thức trước đó với 0 làm đối số giới hạn và trả về kết quả của lệnh gọi.
split(CharSequence text)
giải bài toán chia tài khoản nhân viên thành các trường riêng biệt tên, tuổi, địa chỉ bưu điện và mức lương:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i]);
Đoạn mã trên mô tả một biểu thức chính quy để tìm ký tự dấu phẩy ngay sau một ký tự khoảng trắng. Đây là kết quả thực hiện của nó:
John Doe
47
Hillsboro Road
32000
Vị từ mẫu và API luồng
Trong Java 8,Pattern
một phương thức đã xuất hiện trong lớp . Phương thức này tạo một vị từ (một hàm có giá trị boolean) được sử dụng để khớp với mẫu. Việc sử dụng phương pháp này được hiển thị trong đoạn mã sau: Predicate
asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
Mã này tạo danh sách tên ngôn ngữ lập trình, sau đó biên dịch mẫu để tìm tất cả các tên bắt đầu bằng chữ cái c
. Dòng mã cuối cùng ở trên thực hiện nhận luồng dữ liệu nối tiếp với danh sách này làm nguồn. Nó thiết lập một bộ lọc bằng hàm Boolean asPredicate()
trả về true khi tên bắt đầu bằng một chữ cái c
và lặp qua luồng, in các tên trùng khớp thành đầu ra tiêu chuẩn. Dòng cuối cùng này tương đương với vòng lặp thông thường sau, quen thuộc với ứng dụng RegexDemo ở Phần 1:
for (String progLang: progLangs)
if (p.matcher(progLang).find())
System.out.println(progLang);
Phương thức lớp đối sánh
Một phiên bản của lớpMatcher
mô tả một cơ chế thực hiện các thao tác khớp mẫu trên một chuỗi ký tự bằng cách diễn giải biểu thức chính quy được biên dịch của lớp Pattern
. Các đối tượng của lớp Matcher
hỗ trợ nhiều loại hoạt động tìm kiếm mẫu khác nhau:
-
Phương thức
boolean find()
tìm kiếm văn bản đầu vào cho kết quả khớp tiếp theo. Phương pháp này bắt đầu quét ở đầu văn bản được chỉ định hoặc ở ký tự đầu tiên sau kết quả khớp trước đó. Tùy chọn thứ hai chỉ khả dụng nếu lệnh gọi trước đó tới phương thức này trả về true và trình phân giải không được đặt lại. Trong mọi trường hợp, nếu tìm kiếm thành công, giá trị boolean true sẽ được trả về. Một ví dụ về phương pháp này có thể được tìm thấy trongRegexDemo
Phần 1. -
Phương thức này
boolean find(int start)
đặt lại trình so khớp và tìm kiếm văn bản cho kết quả khớp tiếp theo. Việc xem bắt đầu từ vị trí được chỉ định bởi tham sốstart
. Nếu tìm kiếm thành công, giá trị boolean true sẽ được trả về. Ví dụ:m.find(1);
quét văn bản bắt đầu từ vị trí1
(vị trí 0 bị bỏ qua). Nếu tham sốstart
chứa giá trị âm hoặc giá trị lớn hơn độ dài văn bản so khớp, phương thức sẽ đưa ra một ngoại lệjava.lang.IndexOutOfBoundsException
. -
Phương thức này
boolean matches()
cố gắng khớp tất cả văn bản với một mẫu. Nó trả về giá trị boolean true nếu tất cả văn bản khớp với mẫu. Ví dụ: mãPattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());
xuất rafalse
vì ký tự!
không phải là ký tự từ. -
Phương thức này
boolean lookingAt()
cố gắng khớp văn bản đã cho với mẫu. Phương thức này trả về true nếu bất kỳ phần nào của văn bản khớp với mẫu. Không giống như phương thức nàymatches();
, tất cả văn bản không nhất thiết phải khớp với mẫu. Ví dụ:Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());
nó sẽ xuất ratrue
, vì phần đầu của văn bảnabc!
chỉ bao gồm các ký tự tạo thành từ.
Pattern
, đối tượng lớp Matcher
giữ lại thông tin trạng thái. Đôi khi bạn có thể cần phải đặt lại trình so khớp để xóa thông tin này sau khi quá trình tìm kiếm mẫu kết thúc. Các phương pháp sau đây có sẵn để đặt lại trình phân giải:
-
Phương thức này
Matcher reset()
đặt lại trạng thái của trình so khớp, bao gồm cả vị trí được thêm vào cuối (đặt lại về 0). Hoạt động tìm kiếm mẫu tiếp theo bắt đầu ở đầu văn bản so khớp. Một tham chiếu đến đối tượng hiện tại được trả vềMatcher
. Ví dụ:m.reset();
đặt lại trình phân giải được tham chiếu bởim
. -
Phương thức này
Matcher reset(CharSequence text)
đặt lại trạng thái của trình phân giải và đặt văn bản của trình phân giải mới thànhtext
. Hoạt động tìm kiếm mẫu tiếp theo bắt đầu ở đầu văn bản so khớp mới. Trả về một tham chiếu đến đối tượng hiện tạiMatcher
. Ví dụ:m.reset("new text");
đặt lại trình phân giải được tham chiếum
và đặt văn bản trình phân giải mới thành"new text"
.
Thêm văn bản vào cuối
Vị trí của trình so khớp được thêm vào cuối chỉ định phần đầu của văn bản so khớp được thêm vào cuối đối tượng thuộc loạijava.lang.StringBuffer
. Các phương pháp sau đây sử dụng vị trí này:
-
Phương thức này
Matcher appendReplacement(StringBuffer sb, String replacement)
đọc các ký tự văn bản so khớp và nối chúng vào cuối đối tượngStringBuffer
được tham chiếu bởi đối sốsb
. Phương thức này dừng đọc ở ký tự cuối cùng trước khớp mẫu trước đó. Tiếp theo, phương thức nối các ký tự từ đối tượngString
thuộc loại được đối số tham chiếureplacement
vào cuối đối tượngStringBuffer
(chuỗireplacement
có thể chứa các tham chiếu đến các chuỗi văn bản được ghi lại trong quá trình tìm kiếm trước đó; các ký tự này được chỉ định bằng cách sử dụng các ký tự($)
và số nhóm được ghi lại). Cuối cùng, phương thức này đặt giá trị của vị trí so khớp để nối vào vị trí của ký tự so khớp cuối cùng cộng với một, sau đó trả về một tham chiếu đến so khớp hiện tại. -
Phương thức này
StringBuffer appendTail(StringBuffer sb)
thêm tất cả văn bản vào một đối tượngStringBuffer
và trả về một tham chiếu đến đối tượng đó. Sau lần gọi phương thức cuối cùngappendReplacement(StringBuffer sb, String replacement)
, hãy gọi phương thức nàyappendTail(StringBuffer sb)
để sao chép phần văn bản còn lại vào đối tượngStringBuffer
.
Phương thức này Matcher appendReplacement(StringBuffer sb, String replacement)
sẽ đưa ra một ngoại lệ java.lang.IllegalStateException
nếu trình so khớp chưa tìm thấy kết quả khớp hoặc nỗ lực tìm kiếm trước đó không thành công. Nó đưa ra một ngoại lệ IndexOutOfBoundsException
nếu dòng replacement
chỉ định một nhóm chụp không có trong mẫu).
Nhóm bị bắt |
---|
Như bạn còn nhớ ở Phần 1, một nhóm chụp là một chuỗi các ký tự được đặt trong dấu ngoặc đơn ( () ) siêu ký tự. Mục đích của cấu trúc này là lưu trữ các ký tự tìm thấy để sử dụng lại sau này trong quá trình khớp mẫu. Tất cả các ký tự trong nhóm đã chụp được coi là một tổng thể duy nhất trong quá trình tìm kiếm mẫu. |
appendReplacement(StringBuffer sb, String replacement)
và appendTail(StringBuffer sb
để thay thế tất cả các lần xuất hiện của chuỗi ký tự trong văn bản nguồn cat
bằng caterpillar
:
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
Việc sử dụng một nhóm đã chụp và tham chiếu đến nhóm đó trong văn bản thay thế sẽ yêu cầu chương trình chèn erpillar
sau mỗi lần xuất hiện của cat
. Kết quả thực thi mã này trông như thế này: one caterpillar, two caterpillars, or three caterpillars on a fence
Thay thế văn bản
Lớp nàyMatcher
cung cấp cho chúng ta hai phương thức để thay thế văn bản, bổ sung cho lớp appendReplacement(StringBuffer sb, String replacement)
. Bằng cách sử dụng các phương pháp này, bạn có thể thay thế lần xuất hiện đầu tiên của [văn bản được thay thế] hoặc tất cả các lần xuất hiện:
-
Phương thức này
String replaceFirst(String replacement)
đặt lại trình so khớp, tạo một đối tượng mớiString
, sao chép tất cả các ký tự của văn bản so khớp (cho đến kết quả khớp đầu tiên) vào chuỗi này, nối các ký tự từ đầu đến cuối chuỗi, saoreplacement
chép các ký tự còn lại vào chuỗi và trả về một đối tượngString
(chuỗireplacement
có thể chứa các tham chiếu đến những chuỗi được ghi lại trong chuỗi văn bản tìm kiếm trước đó bằng cách sử dụng ký hiệu đô la và số nhóm được ghi lại). -
Phương thức này
String replaceAll(String replacement)
hoạt động tương tự như phương thứcString replaceFirst(String replacement)
, nhưng thay thếreplacement
tất cả các kết quả khớp được tìm thấy bằng các ký tự trong chuỗi.
\s+
tìm kiếm một hoặc nhiều ký tự khoảng trắng trong văn bản đầu vào. Dưới đây, chúng tôi sẽ sử dụng biểu thức chính quy này và gọi một phương thức replaceAll(String replacement)
để xóa các khoảng trắng trùng lặp:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем \t\t лишние пробелы. ");
System.out.println(m.replaceAll(" "));
Đây là kết quả: Удаляем лишние пробелы.
Biểu thức chính quy trong Java, Phần 4 Biểu thức chính quy trong Java, Phần 5
GO TO FULL VERSION