Java regex nắm bắt chỉ mục nhóm


113

Tôi có dòng sau,

typeName="ABC:xxxxx;";

Tôi cần lấy từ này ABC,

Tôi đã viết đoạn mã sau,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Vì vậy, nếu tôi đặt group(0)tôi nhận được ABC:nhưng nếu tôi đặt group(1)ABC, vì vậy tôi muốn biết

  1. Điều này có gì 01nghĩa là gì? Sẽ tốt hơn nếu ai đó có thể giải thích cho tôi bằng những ví dụ điển hình.

  2. Mẫu regex có chứa a :trong đó, vậy tại sao group(1)kết quả lại bỏ qua điều đó? Nhóm 1 có phát hiện tất cả các từ bên trong dấu ngoặc đơn không?

  3. Vì vậy, nếu tôi đặt thêm hai dấu ngoặc đơn như \\s*(\d*)(.*): sau đó, sẽ có hai nhóm? group(1)sẽ trả lại (\d*)một phần và group(2)trả lại (.*)một phần?

Đoạn mã được đưa ra nhằm mục đích giải tỏa sự nhầm lẫn của tôi. Nó không phải là mã tôi đang xử lý. Đoạn mã được đưa ra ở trên có thể được thực hiện String.split()theo cách dễ dàng hơn nhiều.

Câu trả lời:


182

Chụp và phân nhóm

Chụp nhóm (pattern) tạo ra một nhóm đã chụp tài sản.

Một nhóm có liên quan mà bạn có thể thường thấy (và sử dụng) là (?:pattern), nhóm này tạo một nhóm mà không chiếm thuộc tính, do đó được đặt tên là nhóm không chiếm .

Một nhóm thường được sử dụng khi bạn cần lặp lại một chuỗi các mẫu, ví dụ (\.\w+)+, hoặc để chỉ định nơi mà sự thay thế sẽ có hiệu lực, ví dụ: ^(0*1|1*0)$( ^, sau đó 0*1hoặc 1*0, sau đó $) so với ^0*1|1*0$( ^0*1hoặc 1*0$).

Một nhóm chụp, ngoài việc phân nhóm, cũng sẽ ghi lại văn bản khớp với mẫu bên trong nhóm chụp (pattern). Sử dụng ví dụ của bạn (.*):, .*đối sánh ABC:đối sánh :, và vì .*nằm trong nhóm chụp (.*)nên văn bản ABCđược ghi lại cho nhóm chụp 1.

Số nhóm

Toàn bộ mẫu được xác định là nhóm số 0.

Bất kỳ nhóm thu thập nào trong mẫu bắt đầu lập chỉ mục từ 1. Các chỉ số được xác định theo thứ tự của dấu ngoặc đơn mở của các nhóm thu thập . Ví dụ, đây là tất cả 5 nhóm chụp trong mẫu bên dưới:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Số nhóm được sử dụng trong tham chiếu ngược \ntrong mẫu và $ntrong chuỗi thay thế.

Trong các hương vị regex khác (PCRE, Perl), chúng cũng có thể được sử dụng trong các cuộc gọi phụ .

Bạn có thể truy cập văn bản được so khớp theo nhóm nhất định với Matcher.group(int group). Số nhóm có thể được xác định bằng quy tắc đã nêu ở trên.

Trong một số phiên bản regex (PCRE, Perl), có một tính năng đặt lại nhánh cho phép bạn sử dụng cùng một số để chụp các nhóm trong các nhánh luân phiên khác nhau .

Tên nhóm

Từ Java 7, bạn có thể xác định một nhóm thu thập được đặt tên (?<name>pattern) và bạn có thể truy cập nội dung phù hợp vớiMatcher.group(String name) . Regex dài hơn, nhưng mã có ý nghĩa hơn, vì nó cho biết những gì bạn đang cố gắng khớp hoặc trích xuất với regex.

Tên nhóm được sử dụng trong tham chiếu ngược \k<name>trong mẫu và${name} trong chuỗi thay thế.

Các nhóm bắt được đặt tên vẫn được đánh số với cùng một sơ đồ đánh số, vì vậy chúng cũng có thể được truy cập thông qua Matcher.group(int group).

Bên trong, việc triển khai của Java chỉ ánh xạ từ tên đến số nhóm. Do đó, bạn không thể sử dụng cùng một tên cho 2 nhóm chụp khác nhau.


1
WOW! Cảm ơn bạn @nhahtdh đã giải thích các nhóm không nắm bắt cách hoạt động của thứ tự nhóm lồng nhau. Tôi đã bối rối về cách các số lượng nhóm hoạt động cho đến khi tôi cuối cùng đọc lời giải thích của bạn. Cảm ơn rất nhiều!
MMeah

92

Đối với phần còn lại của chúng tôi

Đây là một ví dụ đơn giản và rõ ràng về cách hoạt động của điều này

Regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

Chuỗi: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Như bạn thấy, tôi đã tạo NĂM nhóm mà mỗi nhóm được đặt trong dấu ngoặc đơn.

Tôi đã bao gồm! * Và *! ở hai bên để làm cho nó rõ ràng hơn. Lưu ý rằng không có ký tự nào trong số đó có trong RegEx và do đó sẽ không được tạo trong kết quả. Nhóm (0) chỉ cung cấp cho bạn toàn bộ chuỗi phù hợp (tất cả các tiêu chí tìm kiếm của tôi trong một dòng duy nhất). Nhóm 1 dừng ngay trước khoảng trắng đầu tiên vì ký tự khoảng trắng không được bao gồm trong tiêu chí tìm kiếm. Nhóm 2 và 4 chỉ đơn giản là khoảng trắng, trong trường hợp này theo nghĩa đen là ký tự khoảng trắng, nhưng cũng có thể là tab hoặc nguồn cấp dòng, v.v. Nhóm 3 bao gồm khoảng trắng vì tôi đã đặt nó trong tiêu chí tìm kiếm ... v.v.

Hy vọng điều này có ý nghĩa.


1
ví dụ hoàn hảo dễ hiểu cho người mới bắt đầu. Tôi nghi ngờ liệu điều này có giống với nhóm reg ex trong python không? hoặc là có bất kỳ sự khác biệt? Tôi mới sử dụng reg ex đó là lý do tại sao tôi hơi bối rối trong cả hai ngôn ngữ.
Mani

1
Đây không phải là một regex Java hợp lệ: dấu gạch chéo ngược phải được nhân đôi.
Nicolas Raoul

1
@NicolasRaoul: Dấu gạch chéo ngược kép là do cú pháp thoát trong chuỗi ký tự. Cú pháp regex thực tế (tức là nếu bạn in chuỗi chứa regex ra bảng điều khiển) không yêu cầu dấu gạch chéo ngược kép.
nhahtdh

@NicolasRaoul Nếu bạn sao chép và dán chuỗi regex của tôi vào mã java thực bằng IDE có thẩm quyền, IDE sẽ định dạng đúng các dấu gạch chéo khi cần thiết. Nhưng Regex của tôi đúng về mặt kỹ thuật và cú pháp và nó phục vụ mục đích chính là chứng minh mối liên hệ giữa mã regex và kết quả thu được (sử dụng một ví dụ rất cụ thể) ... hãy làm sáng tỏ một chút ... ☺
Michael Sims

44

Dấu ngoặc đơn ()được sử dụng để cho phép nhóm các cụm từ regex.

Chuỗi group(1)chứa chuỗi nằm giữa dấu ngoặc đơn (.*)nên.* trong trường hợp này

group(0) chứa toàn bộ chuỗi phù hợp.

Nếu bạn có nhiều nhóm hơn (đọc (...)), nó sẽ được đưa vào các nhóm có chỉ mục tiếp theo (2, 3, v.v.).


2
Vì vậy, tôi đúng khi thêm dấu ngoặc đơn thực sự là để tạo nhóm?
P basak

3
Vâng, chúng tôi có thể nói rằng.
Michal Borek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.