2011-05-16 37 views
109

Trong Java, tôi đang cố gắng trả về tất cả các đối sánh regex cho một mảng nhưng có vẻ như bạn chỉ có thể kiểm tra xem mẫu có khớp với thứ gì đó hay không (boolean). Ai đó có thể giúp tôi sử dụng một trận đấu regex để tạo thành một mảng của tất cả các chuỗi phù hợp với một biểu thức regex trong một chuỗi nhất định? Cảm ơn!Tạo mảng các đối sánh regex

+2

Tốt câu hỏi. Thông tin bạn tìm kiếm phải là một phần của tài liệu Java trên Regex và Matcher. Đáng buồn thay, nó không phải là. – Cheeso

+2

Một sự xấu hổ thực sự.Chức năng này dường như tồn tại trong hộp ở hầu hết các ngôn ngữ khác (có hỗ trợ biểu thức chính quy). –

Trả lời

192

(4castle's answer là tốt hơn so với dưới đây nếu bạn có thể giả định Java> = 9)

bạn cần phải tạo một khớp và sử dụng để lặp đi lặp lại tìm trận đấu.

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

... 

List<String> allMatches = new ArrayList<String>(); 
Matcher m = Pattern.compile("your regular expression here") 
    .matcher(yourStringHere); 
while (m.find()) { 
    allMatches.add(m.group()); 
} 

Sau này, allMatches chứa các trận đấu, và bạn có thể sử dụng allMatches.toArray(new String[0]) để có được một mảng nếu bạn thực sự cần.


Bạn cũng có thể sử dụng để viết MatchResult chức năng helper để lặp qua các trận đấu kể từ Matcher.toMatchResult() lợi nhuận một bản chụp của tình trạng hiện tại của nhóm.

Ví dụ, bạn có thể viết một iterator lười biếng để cho phép bạn làm

for (MatchResult match : allMatches(pattern, input)) { 
    // Use match, and maybe break without doing the work to find all possible matches. 
} 

bằng cách làm một cái gì đó như thế này:

public static Iterable<MatchResult> allMatches(
     final Pattern p, final CharSequence input) { 
    return new Iterable<MatchResult>() { 
    public Iterator<MatchResult> iterator() { 
     return new Iterator<MatchResult>() { 
     // Use a matcher internally. 
     final Matcher matcher = p.matcher(input); 
     // Keep a match around that supports any interleaving of hasNext/next calls. 
     MatchResult pending; 

     public boolean hasNext() { 
      // Lazily fill pending, and avoid calling find() multiple times if the 
      // clients call hasNext() repeatedly before sampling via next(). 
      if (pending == null && matcher.find()) { 
      pending = matcher.toMatchResult(); 
      } 
      return pending != null; 
     } 

     public MatchResult next() { 
      // Fill pending if necessary (as when clients call next() without 
      // checking hasNext()), throw if not possible. 
      if (!hasNext()) { throw new NoSuchElementException(); } 
      // Consume pending so next call to hasNext() does a find(). 
      MatchResult next = pending; 
      pending = null; 
      return next; 
     } 

     /** Required to satisfy the interface, but unsupported. */ 
     public void remove() { throw new UnsupportedOperationException(); } 
     }; 
    } 
    }; 
} 

Với điều này,

for (MatchResult match : allMatches(Pattern.compile("[abc]"), "abracadabra")) { 
    System.out.println(match.group() + " at " + match.start()); 
} 

sản lượng

a at 0 
b at 1 
a at 3 
c at 4 
a at 5 
a at 7 
b at 8 
a at 10 
+2

Tôi sẽ không đề nghị sử dụng một ArrayList ở đây vì bạn không biết trước kích thước và có thể muốn tránh việc thay đổi kích thước bộ đệm. Thay vào đó, tôi muốn một LinkedList - mặc dù nó chỉ là một gợi ý và không làm cho câu trả lời của bạn ít hợp lệ hơn. – Liv

+8

@Liv, dành thời gian để đánh giá cả 'ArrayList' và' LinkedList', kết quả có thể gây ngạc nhiên. –

+0

Tôi nghe những gì bạn đang nói và tôi biết tốc độ thực thi và dấu chân bộ nhớ trong cả hai trường hợp, vấn đề với ArrayList là hàm tạo mặc định tạo ra dung lượng là 10 - nếu bạn vượt qua kích thước đó với các cuộc gọi để thêm() bạn sẽ phải chịu sự phân bổ bộ nhớ và bản sao mảng - và điều đó có thể xảy ra một vài lần. Cấp, nếu bạn mong đợi chỉ là một vài trận đấu thì cách tiếp cận của bạn là một cách hiệu quả hơn; tuy nhiên, nếu bạn thấy rằng mảng "thay đổi kích thước" xảy ra nhiều hơn một lần, tôi sẽ đề xuất một LinkedList, thậm chí nhiều hơn thế nếu bạn đang xử lý một ứng dụng độ trễ thấp. – Liv

8

Dưới đây là một ví dụ đơn giản:

Pattern pattern = Pattern.compile(regexPattern); 
List<String> list = new ArrayList<String>(); 
Matcher m = pattern.matcher(input); 
while (m.find()) { 
    list.add(m.group()); 
} 

(nếu bạn có nhiều nhóm chụp, bạn có thể tham khảo chúng bằng cách chỉ mục của họ như một đối số của phương pháp nhóm Nếu bạn cần một mảng, sau đó sử dụng list.toArray().)

+0

pattern.matches (đầu vào) không hoạt động. Bạn phải vượt qua mẫu regex của bạn (một lần nữa!) -> WTF Java ?! pattern.matches (Chuỗi regex, Chuỗi đầu vào); Bạn có nghĩa là pattern.matcher (đầu vào)? –

+0

@ElMac ['Pattern.matches()'] (http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#matches-java.lang.String-java .lang.CharSequence-) là một phương thức tĩnh, bạn không nên gọi nó trên một cá thể 'Pattern'. 'Pattern.matches (regex, input)' chỉ đơn giản là viết tắt của 'Pattern.compile (regex) .matcher (đầu vào) .matches()'. – dimo414

5

Từ Official Regex Java Trails:

 Pattern pattern = 
     Pattern.compile(console.readLine("%nEnter your regex: ")); 

     Matcher matcher = 
     pattern.matcher(console.readLine("Enter input string to search: ")); 

     boolean found = false; 
     while (matcher.find()) { 
      console.format("I found the text \"%s\" starting at " + 
       "index %d and ending at index %d.%n", 
       matcher.group(), matcher.start(), matcher.end()); 
      found = true; 
     } 

Sử dụng find và chèn kết quả group ở mảng của bạn/Danh sách/bất cứ điều gì.

25

Java làm cho regex quá phức tạp và không tuân theo kiểu perl. Hãy nhìn vào MentaRegex để xem làm thế nào bạn có thể thực hiện điều đó trong một dòng mã Java:

String[] matches = match("aa11bb22", "/(\\d+)/g"); // => ["11", "22"] 
+4

Thật tuyệt. Các dấu gạch chéo đôi vẫn trông xấu xí nhưng tôi đoán không có scape từ đó. – JohnPristine

+0

mentaregex-0.9.5.jar, 6Kb đã lưu lại ngày của tôi, Obrigado Sérgio! –

+2

CHÚ Ý! Giải pháp tốt nhất. Sử dụng nó! –

-1
 Set<String> keyList = new HashSet(); 
     Pattern regex = Pattern.compile("#\\{(.*?)\\}"); 
     Matcher matcher = regex.matcher("Content goes here"); 
     while(matcher.find()) { 
      keyList.add(matcher.group(1)); 
     } 
     return keyList; 
9

Trong Java 9, bây giờ bạn có thể sử dụng Matcher#results() để có được một Stream<MatchResult> mà bạn có thể sử dụng để có được một danh sách/mảng của các kết quả phù hợp.

import java.util.regex.Pattern; 
import java.util.regex.MatchResult; 
String[] matches = Pattern.compile("your regex here") 
          .matcher("string to search from here") 
          .results() 
          .map(MatchResult::group) 
          .toArray(String[]::new); 
        // or .collect(Collectors.toList()) 
Các vấn đề liên quan