Các nhóm bắt giữ Regex Java


170

Tôi đang cố gắng để hiểu khối mã này. Trong cái đầu tiên, chúng ta đang tìm kiếm cái gì trong biểu thức?

Tôi hiểu rằng đó là bất kỳ ký tự nào (0 hoặc nhiều lần *) được theo sau bởi bất kỳ số nào trong khoảng từ 0 đến 9 (một hoặc nhiều lần +) theo sau bởi bất kỳ ký tự nào (0 hoặc nhiều lần *).

Khi điều này được thực hiện, kết quả là:

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

Ai đó có thể xin vui lòng thông qua điều này với tôi?

Lợi thế của việc sử dụng các nhóm Chụp là gì?

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTut3 {

    public static void main(String args[]) {
        String line = "This order was placed for QT3000! OK?"; 
        String pattern = "(.*)(\\d+)(.*)";

        // Create a Pattern object
        Pattern r = Pattern.compile(pattern);

        // Now create matcher object.
        Matcher m = r.matcher(line);

        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }

}

1
Để chèn một dòng mới, đặt 2 khoảng trắng ở cuối dòng. Tìm hiểu thêm về cú pháp đánh dấu: en.wikipedia.org/wiki/Markdown - Xem thêm: stackoverflow.com/editing-help
assylias

Câu trả lời:


248

Vấn đề bạn gặp phải là với loại định lượng. Bạn đang sử dụng bộ định lượng tham lam trong nhóm đầu tiên của mình (chỉ số 1 - chỉ số 0 đại diện cho toàn bộ Pattern), có nghĩa là nó sẽ khớp nhiều nhất có thể (và vì nó là bất kỳ ký tự nào , nên nó sẽ khớp với nhiều ký tự như có để đáp ứng điều kiện cho các nhóm tiếp theo).

Nói tóm lại, nhóm 1 của bạn .*khớp với bất cứ thứ gì miễn là nhóm tiếp theo \\d+có thể khớp với thứ gì đó (trong trường hợp này là chữ số cuối cùng).

Theo nhóm thứ 3, nó sẽ khớp với bất cứ thứ gì sau chữ số cuối cùng.

Nếu bạn thay đổi nó thành một bộ định lượng miễn cưỡng trong nhóm 1 của bạn, bạn sẽ nhận được kết quả mà tôi cho rằng bạn đang mong đợi, đó là phần 3000 .

Lưu ý các dấu hỏi trong nhóm 1.

String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
    System.out.println("group 1: " + matcher.group(1));
    System.out.println("group 2: " + matcher.group(2));
    System.out.println("group 3: " + matcher.group(3));
}

Đầu ra:

group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?

Thêm thông tin về Java Pattern tại đây .

Cuối cùng, các nhóm chụp được phân định bằng dấu ngoặc tròn và cung cấp một cách rất hữu ích để sử dụng tham chiếu ngược (trong số những thứ khác), khi bạn Patternkhớp với đầu vào.

Trong Java 6, các nhóm chỉ có thể được tham chiếu theo thứ tự của chúng (hãy cẩn thận với các nhóm lồng nhau và sự tinh tế của việc đặt hàng).

Trong Java 7, điều đó dễ dàng hơn nhiều, vì bạn có thể sử dụng các nhóm được đặt tên.


Cảm ơn! Có phải lý do nhóm 2 được lưu 0 vì toàn bộ dòng được sử dụng bởi bộ định lượng tham lam sau đó tắt đi cho đến khi nó tiếp xúc với một hoặc nhiều số. 0 thỏa mãn điều này nên biểu hiện đã thành công. Tôi thấy nhóm thứ ba khó hiểu, phải chăng bộ định lượng tham lam đó cũng tiêu thụ toàn bộ dòng, nhưng lùi lại cho đến khi tìm thấy một hoặc nhiều số (\\ d +) được cho là trước nó?
Xivilai

@Xivilai hãy để tôi điều chỉnh lời giải thích trong câu trả lời của mình, chỉ một giây thôi.
Mena

Đó là một lời giải thích tốt. Vì vậy, sự miễn cưỡng bắt đầu từ bên trái và chỉ mất tối thiểu trong khi với người tham lam, sẽ mất càng nhiều càng tốt (bắt đầu từ bên phải), chỉ dừng lại trước chữ số cuối cùng để thỏa mãn điều kiện đó. Nhóm thứ ba lấy phần còn lại.
Xivilai

@Xivilai nhiều hay ít. Nó luôn luôn bắt đầu từ bên trái mặc dù trong trường hợp này. Dưới đây là một số thông tin thêm về định lượng.
Mena

2
Bạn có thể sử dụng các nhóm chụp có tên trong Java 5/6 với named-regexp.

16

Điều này là hoàn toàn OK.

  1. Nhóm đầu tiên ( m.group(0)) luôn chụp toàn bộ khu vực được bao phủ bởi biểu thức chính quy của bạn . Trong trường hợp này, đó là toàn bộ chuỗi.
  2. Các biểu thức thông thường là tham lam theo mặc định, có nghĩa là nhóm đầu tiên nắm bắt càng nhiều càng tốt mà không vi phạm regex. (.*)(\\d+)( Phần đầu tiên trong regex của bạn) bao gồm ...QT300int nhóm đầu tiên và0 thứ hai.
  3. Bạn có thể nhanh chóng khắc phục điều này bằng cách làm cho nhóm đầu tiên không tham lam: thay đổi (.*)thành (.*?).

Để biết thêm thông tin về tham lam so với lười biếng, hãy kiểm tra trang web này.


4

Từ tài liệu:

Capturing groups</a> are indexed from left
 * to right, starting at one.  Group zero denotes the entire pattern, so
 * the expression m.group(0) is equivalent to m.group().

Vì vậy, chụp nhóm 0 gửi toàn bộ dòng.


3

Sự am hiểu của bạn đa đung đăn. Tuy nhiên, nếu chúng ta đi qua:

  • (.*) sẽ nuốt cả chuỗi;
  • nó sẽ cần phải trả lại các ký tự sao cho phù hợp (\\d+)(đó là lý do tại sao0 bị bắt và không 3000);
  • cuối cùng (.*) sau đó sẽ nắm bắt phần còn lại.

Tuy nhiên, tôi không chắc ý định ban đầu của tác giả là gì.

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.