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

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

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 2 - 1Biểu thức chính quy trong Java, Phần 1
Hợp nhất nhiều phạm vi
Bạn có thể hợp nhất nhiều phạm vi thành một lớp ký tự phạm vi duy nhất bằng cách đặt chúng cạnh nhau. Ví dụ: lớp [a-zA-Z]khớp với tất cả các ký tự chữ cái Latinh ở dạng chữ thường hoặc chữ hoa.

Hợp nhất nhiều phạm vi

Bạn có thể hợp nhất nhiều phạm vi thành một lớp ký tự phạm vi duy nhất bằng cách đặt chúng cạnh nhau. Ví dụ: lớp [a-zA-Z]khớp với tất cả các ký tự chữ cái Latinh ở dạng chữ thường hoặc chữ hoa.

Kết hợp các lớp nhân vật

Một liên kết lớp ký tự bao gồm một số lớp ký tự lồng nhau và khớp với tất cả các ký tự trong liên kết kết quả. Ví dụ: lớp [a-d[m-p]]khớp các ký tự từ ađến dvà từ mtới p. Hãy xem xét ví dụ sau: java RegexDemo [ab[c-e]] abcdef Ví dụ này sẽ tìm các ký tự a, b, và , có các ký tự trùng khớp trong c:deabcdef
regex = [ab[c-e]]
input = abcdef
Found [a] starting at 0 and ending at 0
Found [b] starting at 1 and ending at 1
Found [c] starting at 2 and ending at 2
Found [d] starting at 3 and ending at 3
Found [e] starting at 4 and ending at 4

Giao điểm lớp nhân vật

Giao của các lớp ký tự bao gồm các ký tự chung cho tất cả các lớp lồng nhau và chỉ khớp với các ký tự chung. Ví dụ: lớp [a-z&&[d-f]]khớp với các ký tự d, ef. Hãy xem xét ví dụ sau: java RegexDemo "[aeiouy&&[y]]" party Lưu ý rằng trên hệ điều hành Windows của tôi, cần có dấu ngoặc kép vì shell lệnh coi chúng &như dấu phân cách lệnh. Ví dụ này sẽ chỉ tìm thấy ký tự ykhớp với party:
regex = [aeiouy&&[y]]
input = party
Found [y] starting at 4 and ending at 4

Trừ các lớp ký tự

Các lớp ký tự trừ bao gồm tất cả các ký tự ngoại trừ các ký tự có trong các lớp ký tự lồng nhau và chỉ khớp với các ký tự còn lại. Ví dụ: lớp [a-z&&[^m-p]]khớp các ký tự từ đến altừ qđến z: java RegexDemo "[a-f&&[^a-c]&&[^e]]" abcdefg Ví dụ này sẽ tìm các ký tự dfcó các ký tự khớp trong abcdefg:
regex = [a-f&&[^a-c]&&[^e]]
input = abcdefg
Found [d] starting at 3 and ending at 3
Found [f] starting at 5 and ending at 5

Các lớp ký tự được xác định trước

Một số lớp ký tự xuất hiện đủ thường xuyên trong các biểu thức chính quy để biện minh cho việc sử dụng ký hiệu tốc ký. Lớp này Patterncung cấp các lớp ký tự được xác định trước dưới dạng viết tắt như vậy. Bạn có thể sử dụng chúng để đơn giản hóa biểu thức chính quy và giảm thiểu lỗi cú pháp. Có một số loại lớp ký tự được xác định trước: thuộc tính tiêu chuẩn, POSIX java.lang.Charactervà Unicode như tập lệnh, khối, danh mục và nhị phân. Danh sách sau đây chỉ hiển thị danh mục các lớp tiêu chuẩn:
  • \d: Con số. Tương đương [0-9].
  • \D: Ký tự không phải số. Tương đương [^0-9].
  • \s: Ký tự khoảng trắng. Tương đương [ \t\n\x0B\f\r].
  • \S: Không phải là ký tự khoảng trắng. Tương đương [^\s].
  • \w: Ký hiệu tạo thành từ. Tương đương [a-zA-Z_0-9].
  • \W: Không phải là ký tự tạo thành từ. Tương đương [^\w].
Ví dụ sau sử dụng lớp ký tự được xác định trước \wđể mô tả tất cả các ký tự từ trong văn bản đầu vào: java RegexDemo \w "aZ.8 _" Hãy xem xét kỹ các kết quả thực thi sau đây, cho thấy các ký tự dấu chấm và dấu cách không được coi là ký tự từ:
regex = \w
input = aZ.8 _
Found [a] starting at 0 and ending at 0
Found [Z] starting at 1 and ending at 1
Found [8] starting at 3 and ending at 3
Found [_] starting at 5 and ending at 5
Dấu phân cách dòng
Tài liệu SDK lớp Patternmô tả siêu ký tự dấu chấm là một lớp ký tự được xác định trước khớp với bất kỳ ký tự nào ngoại trừ dấu phân cách dòng (chuỗi một hoặc hai ký tự đánh dấu sự kết thúc của một dòng). Ngoại lệ là chế độ dotall (chúng ta sẽ thảo luận tiếp theo), trong đó các dấu chấm cũng khớp với dấu phân cách dòng. Lớp Patternphân biệt các dấu phân cách dòng sau:
  • ký tự trả về vận chuyển ( \r);
  • ký tự dòng mới (ký hiệu để nâng cấp giấy lên một dòng) ( \n);
  • một ký tự trả về đầu dòng ngay sau đó là một ký tự dòng mới ( \r\n);
  • ký tự dòng tiếp theo ( \u0085);
  • ký tự phân cách dòng ( \u2028);
  • ký hiệu phân cách đoạn văn ( \u2029)

Nhóm bị bắt

Nhóm chụp được sử dụng để lưu bộ ký tự tìm thấy để sử dụng tiếp khi tìm kiếm theo mẫu. Cấu trúc này là một chuỗi các ký tự được bao bọc trong các siêu ký tự bằng dấu ngoặc đơn ( ( )). Tất cả các ký tự trong nhóm đã chụp được coi là một tổng thể duy nhất khi tìm kiếm theo mẫu. Ví dụ: nhóm chụp ( Java) kết hợp các chữ cái J, avthành amột đơn vị. Nhóm chụp này tìm thấy tất cả các lần xuất hiện của mẫu Javatrong văn bản đầu vào. Với mỗi trận đấu, các ký tự được lưu trữ trước đó Javasẽ được thay thế bằng các ký tự tiếp theo. Các nhóm đã chụp có thể được lồng trong các nhóm đã chụp khác. Ví dụ: trong biểu thức chính quy, (Java( language))một nhóm (language)được lồng bên trong một nhóm (Java). Mỗi nhóm chụp lồng nhau hoặc không lồng nhau được gán một số, bắt đầu từ 1 và đánh số từ trái sang phải. Trong ví dụ trước, (Java( language))khớp với nhóm thu thập số 1 và (language)khớp với nhóm thu thập số 2. Trong biểu thức chính quy (a)(b), (a)khớp với nhóm thu thập số 1 và (b)nhóm thu thập số 2. Biểu thức chính quy trong Java, Phần 2 - 2Sau này, có thể truy cập các kết quả trùng khớp được lưu trữ bởi các nhóm thu thập bằng cách sử dụng tham chiếu ngược. Được chỉ định là ký tự dấu gạch chéo ngược, theo sau là ký tự số tương ứng với số lượng của nhóm được thu thập, phản hồi ngược cho phép bạn tham chiếu đến các ký tự trong văn bản được nhóm thu thập. Việc có liên kết ngược khiến trình so khớp tham chiếu đến kết quả tìm kiếm được lưu trữ của nhóm đã thu thập dựa trên số từ kết quả đó, sau đó sử dụng các ký tự từ kết quả đó để thử tìm kiếm thêm. Ví dụ sau đây cho thấy việc sử dụng phản hồi ngược để tìm lỗi ngữ pháp trong văn bản: java RegexDemo "(Java( language)\2)" "The Java language language" Ví dụ này (Java( language)\2)sử dụng biểu thức chính quy để tìm lỗi ngữ pháp có từ trùng lặp languagengay sau Javatrong văn bản đầu vào "The Java language language". Biểu thức chính quy này chỉ định hai nhóm cần nắm bắt: số 1 – (Java( language)\2), tương ứng với Java language languagevà số 2 – (language), tương ứng với ký tự khoảng trắng theo sau là language. Tham chiếu ngược \2cho phép xem lại kết quả được lưu trữ của nhóm số 2 để trình so khớp có thể tìm kiếm lần xuất hiện thứ hai của khoảng trắng theo sau là language, ngay sau lần xuất hiện đầu tiên của khoảng trắng và language. Kết quả của matcher RegexDemonhư sau:
regex = (Java( language)\2)
input = The Java language language
Found [Java language language] starting at 4 and ending at 25

Công cụ so khớp ranh giới

Đôi khi bạn cần thực hiện khớp mẫu ở đầu dòng, ở ranh giới từ, ở cuối văn bản, v.v. Bạn có thể thực hiện việc này bằng cách sử dụng một trong các trình so khớp cạnh lớp Pattern, là các cấu trúc biểu thức chính quy tìm kiếm các kết quả khớp ở các vị trí sau:
  • ^: Bắt đầu dòng;
  • $: Kết thúc dòng;
  • \b: Ranh giới từ;
  • \B: Ranh giới giả;
  • \A: Bắt đầu văn bản;
  • \G: Kết thúc trận đấu trước;
  • \Z: Kết thúc văn bản, không bao gồm dấu phân cách dòng cuối (nếu có);
  • \z: Kết thúc văn bản
Ví dụ sau đây sử dụng ^siêu ký tự so khớp ranh giới để tìm các dòng bắt đầu bằng The, theo sau là 0 hoặc nhiều ký tự từ: java RegexDemo "^The\w*" Therefore Ký tự này ^chỉ định rằng ba ký tự đầu tiên của văn bản đầu vào phải khớp với các ký tự mẫu liên tiếp Th, ecó thể được theo sau bởi bất kỳ số nào của các ký hiệu tạo thành từ. Đây là kết quả của việc thực hiện:
regex = ^The\w*
input = Therefore
Found [Therefore] starting at 0 and ending at 8
Điều gì xảy ra nếu bạn thay đổi dòng lệnh thành java RegexDemo "^The\w*" " Therefore"? Sẽ không tìm thấy kết quả trùng khớp nào vì Thereforevăn bản đầu vào được đặt trước ký tự khoảng trắng.

Trận đấu có độ dài bằng 0

Đôi khi, khi làm việc với các công cụ so khớp cạnh, bạn sẽ gặp phải các kết quả khớp có độ dài bằng 0. Совпадение нулевой длиныlà một kết quả khớp không chứa bất kỳ ký tự nào. Chúng có thể xuất hiện trong văn bản đầu vào trống, ở đầu văn bản đầu vào, sau ký tự cuối cùng của văn bản đầu vào và giữa hai ký tự bất kỳ của văn bản đầu vào. Các trận đấu có độ dài bằng 0 rất dễ nhận biết vì chúng luôn bắt đầu và kết thúc ở cùng một vị trí. Hãy xem xét ví dụ sau: java RegExDemo \b\b "Java is" Ví dụ này tìm kiếm hai ranh giới từ liên tiếp và kết quả trông như thế này:
regex = \b\b
input = Java is
Found [] starting at 0 and ending at -1
Found [] starting at 4 and ending at 3
Found [] starting at 5 and ending at 4
Found [] starting at 7 and ending at 6
Chúng tôi thấy một số kết quả trùng khớp có độ dài bằng 0 trong kết quả. Các vị trí kết thúc ở đây ít hơn một vị trí so với các vị trí bắt đầu, vì RegexDemotôi đã chỉ định trong mã nguồn trong Liệt kê 1 end() – 1. Biểu thức chính quy trong Java, Phần 2 - 3

định lượng

Bộ định lượng là một cấu trúc biểu thức chính quy liên kết rõ ràng hoặc ngầm định một mẫu với một giá trị số. Giá trị số này xác định số lần tìm kiếm mẫu. Các định lượng được chia thành tham lam, lười biếng và siêu tham lam:
  • Bộ định lượng tham lam ( ?, *hoặc +) được thiết kế để tìm kết quả khớp dài nhất. Tôi có thể hỏi không X? để tìm một hoặc ít lần xuất hiện X, X*tìm không hoặc nhiều lần xuất hiện X, X+tìm một hoặc nhiều lần xuất hiện X, X{n}tìm nlần xuất hiện X, X{n,}tìm ít nhất (và có thể nhiều hơn) nlần xuất hiện , XX{n,m}tìm ít nhất nhưng không nhiều lần xuất hiện nhơn .mX
  • Bộ định lượng lười biếng ( ??, *?hoặc +?) được thiết kế để tìm kết quả khớp ngắn nhất. Bạn có thể chỉ định X??tìm kiếm một hoặc ít lần xuất hiện của X, X*? để tìm không hoặc nhiều lần xuất hiện X, X+?tìm một hoặc nhiều lần xuất hiện X, X{n}?tìm nlần xuất hiện X, X{n,}?tìm ít nhất (và có thể nhiều hơn) nlần xuất hiện X, và X{n,m}?tìm ít nhất nnhưng không nhiều hơn msố lần xuất hiện X.
  • Bộ định lượng siêu tham lam ( ?+, *+hoặc ++) tương tự như bộ định lượng tham lam, ngoại trừ bộ định lượng siêu tham lam chỉ thực hiện một nỗ lực để tìm ra kết quả khớp dài nhất, trong khi bộ định lượng tham lam có thể thực hiện nhiều lần thử. Có thể được đặt X?+để tìm một hoặc ít lần xuất hiện X, X*+tìm không hoặc nhiều lần xuất hiện X, X++tìm một hoặc nhiều lần xuất hiện X, X{n}+tìm nlần xuất hiện của X, X{n,}+tìm ít nhất (và có thể nhiều hơn) nlần xuất hiện XX{n,m}+ tìm ít nhất nnhưng không nhiều hơn msố lần xuất hiện X.
Ví dụ sau minh họa việc sử dụng bộ lượng hóa tham lam: java RegexDemo .*ox "fox box pox" Đây là kết quả:
regex = .*ox
input = fox box pox
Found [fox box pox] starting at 0 and ending at 10
Bộ định lượng tham lam ( .*) tìm chuỗi ký tự dài nhất kết thúc bằng ox. Nó tiêu thụ toàn bộ văn bản đầu vào và sau đó cuộn lại cho đến khi phát hiện văn bản đầu vào kết thúc bằng các ký tự này. Bây giờ hãy xem xét bộ định lượng lười biếng: java RegexDemo .*?ox "fox box pox" Kết quả của nó:
regex = .*?ox
input = fox box pox
Found [fox] starting at 0 and ending at 2
Found [ box] starting at 3 and ending at 6
Found [ pox] starting at 7 and ending at 10
Bộ định lượng lười biếng ( .*?) tìm chuỗi ký tự ngắn nhất kết thúc bằng ox. Nó bắt đầu bằng một chuỗi trống và dần dần tiêu thụ các ký tự cho đến khi tìm thấy kết quả khớp. Và sau đó tiếp tục làm việc cho đến khi hết văn bản đầu vào. Cuối cùng, chúng ta hãy nhìn vào bộ định lượng siêu tham lam: java RegexDemo .*+ox "fox box pox" Và đây là kết quả của nó:
regex = .*+ox
input = fox box pox
Bộ định lượng cực kỳ tham lam ( .*+) không tìm thấy kết quả khớp vì nó tiêu thụ tất cả văn bản đầu vào và không còn gì để khớp oxở cuối biểu thức chính quy. Không giống như bộ định lượng tham lam, bộ định lượng siêu tham lam không quay trở lại.

Trận đấu có độ dài bằng 0

Đôi khi khi làm việc với bộ định lượng, bạn sẽ gặp phải các kết quả khớp có độ dài bằng 0. Ví dụ: việc sử dụng bộ định lượng tham lam sau đây sẽ dẫn đến nhiều kết quả khớp có độ dài bằng 0: java RegexDemo a? abaa Kết quả khi chạy ví dụ này:
regex = a?
input = abaa
Found [a] starting at 0 and ending at 0
Found [] starting at 1 and ending at 0
Found [a] starting at 2 and ending at 2
Found [a] starting at 3 and ending at 3
Found [] starting at 4 and ending at 3
Có năm kết quả phù hợp trong kết quả thực hiện. Mặc dù chữ thứ nhất, thứ ba và thứ tư khá được mong đợi (chúng tương ứng với vị trí của ba chữ cái atrong abaa), nhưng chữ thứ hai và thứ năm có thể làm bạn ngạc nhiên. Có vẻ như họ chỉ ra những gì atương ứng bvới phần cuối của văn bản, nhưng thực tế không phải vậy. Biểu thức chính quy a?không tìm kiếm bở cuối văn bản. Nó tìm kiếm sự hiện diện hay vắng mặt a. Khi a?nó không tìm thấy a, nó báo cáo nó là kết quả khớp có độ dài bằng 0.

Biểu thức cờ lồng nhau

Trình so khớp đưa ra một số giả định mặc định có thể bị ghi đè khi biên dịch biểu thức chính quy thành một mẫu. Chúng ta sẽ thảo luận vấn đề này sau. Biểu thức chính quy cho phép bạn ghi đè bất kỳ giá trị mặc định nào bằng cách sử dụng biểu thức cờ lồng nhau. Cấu trúc biểu thức chính quy này được chỉ định dưới dạng siêu ký tự trong dấu ngoặc đơn xung quanh siêu ký tự dấu chấm hỏi ( ?), theo sau là một chữ cái Latinh viết thường. Lớp này Patternhiểu các biểu thức cờ lồng nhau sau đây:
  • (?i): Cho phép khớp mẫu không phân biệt chữ hoa chữ thường. Ví dụ: khi sử dụng lệnh, java RegexDemo (?i)tree Treehousechuỗi ký Treetự khớp với mẫu tree. Mặc định là tìm kiếm mẫu phân biệt chữ hoa chữ thường.
  • (?x): Cho phép sử dụng các ký tự khoảng trắng và nhận xét bắt đầu bằng siêu ký tự trong mẫu #. Người so khớp sẽ bỏ qua cả hai. Ví dụ: đối với java RegexDemo ".at(?x)#match hat, cat, and so on" mattermột chuỗi ký tự matkhớp với mẫu .at. Theo mặc định, các ký tự khoảng trắng và nhận xét không được phép và trình so khớp coi chúng là các ký tự liên quan đến tìm kiếm.
  • (?s): Bật chế độ dotall, trong đó siêu ký tự dấu chấm khớp với dấu phân cách dòng ngoài bất kỳ ký tự nào khác. Ví dụ: lệnh java RegexDemo (?s). \nsẽ tìm ký tự dòng mới. Giá trị mặc định ngược lại với dotall: không tìm thấy dấu phân cách dòng. Ví dụ: lệnh Java RegexDemo . \nsẽ không tìm thấy ký tự dòng mới.
  • (?m): Kích hoạt chế độ nhiều dòng, trong đó nó ^khớp với phần đầu và $phần cuối của mỗi dòng. Ví dụ: java RegexDemo "(?m)^abc$" abc\nabctìm cả hai chuỗi trong văn bản đầu vào abc. Theo mặc định, chế độ một dòng được sử dụng: ^khớp với phần đầu của toàn bộ văn bản đầu vào và $khớp với phần cuối của văn bản đó. Ví dụ: java RegexDemo "^abc$" abc\nabctrả về phản hồi không có kết quả trùng khớp.
  • (?u): Cho phép căn chỉnh chữ hoa chữ thường theo Unicode. Cờ này, khi được sử dụng cùng với (?i), cho phép khớp mẫu không phân biệt chữ hoa chữ thường theo tiêu chuẩn Unicode. Cài đặt mặc định là chỉ tìm kiếm các ký tự phân biệt chữ hoa chữ thường và US-ASCII.
  • (?d): Bật chế độ chuỗi kiểu Unix, trong đó trình so khớp nhận dạng siêu ký tự trong ngữ cảnh .và chỉ dấu phân cách dòng . Mặc định là chế độ chuỗi kiểu không phải Unix: trình so khớp nhận ra, trong ngữ cảnh của các siêu ký tự ở trên, tất cả các dấu phân cách dòng.^$\n
Các biểu thức cờ lồng nhau giống với các nhóm đã bắt vì các ký tự của chúng được bao quanh bởi các siêu ký tự dấu ngoặc đơn. Không giống như các nhóm đã nắm bắt, các biểu thức cờ lồng nhau là một ví dụ về các nhóm không được nắm bắt, là một cấu trúc biểu thức chính quy không nắm bắt các ký tự văn bản. Chúng được định nghĩa là chuỗi các ký tự được bao quanh bởi các siêu ký tự trong dấu ngoặc đơn.
Chỉ định nhiều biểu thức cờ lồng nhau
Có thể chỉ định nhiều biểu thức cờ lồng nhau trong một biểu thức chính quy bằng cách đặt chúng cạnh nhau ( (?m)(?i))) hoặc đặt các chữ cái xác định chúng một cách tuần tự ( (?mi)).

Phần kết luận

Như bạn có thể đã nhận ra cho đến bây giờ, biểu thức chính quy cực kỳ hữu ích và thậm chí còn trở nên hữu ích hơn khi bạn nắm vững các sắc thái cú pháp của chúng. Cho đến nay tôi đã giới thiệu cho bạn những kiến ​​thức cơ bản về biểu thức chính quy và Pattern. Trong Phần 2, chúng ta sẽ tìm hiểu sâu hơn về API Regex và khám phá các phương thức của Pattern, MatcherPatternSyntaxException. Tôi cũng sẽ chỉ cho bạn hai ứng dụng thực tế của API Regex mà bạn có thể sử dụng ngay trong các chương trình của mình. Biểu thức chính quy trong Java, Phần 3 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