JavaRush /Blog Java /Random-VI /Biểu thức chính quy trong Java, Phần 3

Biểu thức chính quy trong Java, Phần 3

Xuất bản trong nhóm
Chúng tôi xin giới thiệu với bạn bản dịch hướng dẫn ngắn gọn về các biểu thức chính quy trong Java, do Jeff Friesen viết cho trang web javaworld . Để dễ đọc, chúng tôi chia bài viết thành nhiều phần. Biểu thức chính quy trong Java, Phần 3 - 1Biểu thức chính quy trong Java, Phần 1 Biểu thức chính quy trong Java, Phần 2

Đơ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ày Patternvà 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 PatternMatcher. PatternSyntaxExceptionBạ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

PatternMatcherPatternSyntaxExceptionba 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ớp Patternlà 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 dung regexthành một biểu diễn trung gian được lưu trữ trong một tệp Pattern. 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ệ PatternSyntaxExceptionnế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ớp Matcherđược sử dụng Patternhoặ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ữ Patternbiể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 đến flags: một tập hợp các hằng số bit cho cờ bit thuộc loại OR. Lớp này Patternkhai báo các hằng số CANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINEScó 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.MULTILINEvà biểu thức cờ lồng nhau (?m)thực hiện điều tương tự.
Đôi khi cần có một bản sao chuỗi gốc của biểu thức chính quy được biên dịch thành một đối tượng 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ệp Pattern.

  • int flags()trả về cờ của đối tượng Pattern.
Sau khi nhận được đối tượng 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 Matchertìm kiếm văn bản inputphù 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 Patterncho phép bạn tiết kiệm việc tạo đối tượng PatternMatchertì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 inputmẫ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 onlychỉ chứa dấu cách và ký tự chữ thường.
Biểu thức chính quy trong Java, Phần 3 - 2

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ày Patterncung 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 chia texttheo các kết quả khớp được tìm thấy với mẫu đối tượng Patternvà 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 trong text.

    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-1kết quả trùng khớp và độ dài của mảng không quá limitphầ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ỏ.

  • 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.
Dưới đây là kết quả của phương pháp 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, Patternmộ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 cvà 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ớp Matchermô 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 Matcherhỗ 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 trong RegexDemoPhầ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ố startchứ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 ra falsevì 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ày matches();, 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 ra true, vì phần đầu của văn bản abc!chỉ bao gồm các ký tự tạo thành từ.

Không giống như các đối tượng lớp Pattern, đối tượng lớp Matchergiữ 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ởi m.

  • 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ành text. 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ại Matcher. Ví dụ: m.reset("new text");đặt lại trình phân giải được tham chiếu mvà đặt văn bản trình phân giải mới thành "new text".

Biểu thức chính quy trong Java, Phần 3 - 3

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ại java.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ượng StringBufferđượ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ượng Stringthuộc loại được đối số tham chiếu replacementvào cuối đối tượng StringBuffer(chuỗi replacementcó 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 Matcher appendReplacement(StringBuffer sb, String replacement)sẽ đưa ra một ngoại lệ java.lang.IllegalStateExceptionnế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ệ IndexOutOfBoundsExceptionnếu dòng replacementchỉ định một nhóm chụp không có trong mẫu).

  • 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ượng StringBuffervà trả về một tham chiếu đến đối tượng đó. Sau lần gọi phương thức cuối cùng appendReplacement(StringBuffer sb, String replacement), hãy gọi phương thức này appendTail(StringBuffer sb)để sao chép phần văn bản còn lại vào đối tượng StringBuffer.

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.
Đoạn mã sau gọi các phương thức appendReplacement(StringBuffer sb, String replacement)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 catbằ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 erpillarsau 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ày Matchercung 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ới String, 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, sao replacementchép các ký tự còn lại vào chuỗi và trả về một đối tượng String(chuỗi replacementcó 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ức String replaceFirst(String replacement), nhưng thay thế replacementtất cả các kết quả khớp được tìm thấy bằng các ký tự trong chuỗi.

Biểu thức chính quy \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
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION