2015-12-14 17 views
10

đây là regex của tôi:Nhiều trận đấu với delimiter

([+-]*)(\\d+)\\s*([a-zA-Z]+) 
  • nhóm no.1 = ký
  • nhóm số 2 = số nhân
  • nhóm đơn vị số 3 = thời gian

Điều này là, tôi muốn khớp với đầu vào đã cho nhưng nó có thể bị "chuỗi". Vì vậy, đầu vào của tôi nên hợp lệ nếu và chỉ khi toàn bộ mẫu lặp lại mà không có bất kỳ điều gì giữa các lần xuất hiện đó (ngoại trừ khoảng trắng). (Chỉ một trận đấu hoặc nhiều trận đấu bên cạnh nhau với các khoảng trống có thể giữa chúng).

ví dụ hợp lệ:

1day 
+1day 
-1 day 
+1day-1month 
+1day +1month 
    +1day +1month  

ví dụ không hợp lệ:

###+1day+1month 
+1day###+1month 
+1day+1month### 
###+1day+1month### 
###+1day+1month### 

tôi trường hợp của tôi, tôi có thể sử dụng matcher.find() phương pháp

, điều này sẽ làm các trick nhưng nó sẽ chấp nhận đầu vào như thế này: +1day###+1month không hợp lệ đối với tôi.

Bất kỳ ý tưởng nào? Điều này có thể được giải quyết với nhiều điều kiện IF và nhiều kiểm tra cho các chỉ mục bắt đầu và kết thúc nhưng tôi đang tìm kiếm giải pháp thanh lịch.

EDIT

Các regex gợi ý trong ý kiến ​​dưới đây ^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ sẽ phần nào làm các trick nhưng nếu tôi sử dụng nó trong các mã dưới nó trả về kết quả khác với kết quả tôi đang tìm kiếm. Vấn đề là tôi không thể sử dụng (*my regex*)+ vì nó sẽ khớp với toàn bộ sự việc.

Các giải pháp có thể để phù hợp với toàn bộ đầu vào với ^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ và sau đó sử dụng ([+-]*)(\\d+)\\s*([a-zA-Z]+) với matcher.find()matcher.group(i) để trích xuất mỗi trận đấu và nhóm của mình. Nhưng tôi đang tìm kiếm giải pháp thanh lịch hơn.

Trả lời

7

này nên làm việc cho bạn:

^\s*(([+-]*)(\d+)\s*([a-zA-Z]+)\s*)+$ 

Thứ nhất, bằng cách thêm đầu và kết thúc neo (^$), mô hình sẽ không cho phép ký tự không hợp lệ để xảy ra bất cứ nơi nào trước hoặc sau trận đấu.

Tiếp theo, tôi đã bao gồm khoảng trắng tùy chọn trước và sau mẫu lặp lại (\s*).

Cuối cùng, toàn bộ mẫu được đặt trong bộ lặp để nó có thể xuất hiện nhiều lần liên tiếp ((...)+).

Một mặt, lưu ý, tôi cũng khuyên bạn nên thay đổi [+-]* thành [+-]? để chỉ có thể xảy ra một lần.

Online Demo

+0

Thx, để trả lời. Bạn nói đúng, nhưng tôi đã không mô tả nó một cách chính xác. Nếu đầu vào của tôi là hợp lệ thì tôi cần phải trích xuất cho mỗi khớp với giá trị đơn vị dấu, số nhân và thời gian. Với giải pháp của bạn, nó sẽ trả về '+ 1 ngày + 1 tháng' thành 1 trận đấu thay vì hai '+ 1 ngày' và '+ 1 tháng' – user1610458

+0

Bạn chắc chắn có thể lặp qua tất cả các nhóm trong trận đấu. Nếu điều đó không hoạt động tốt cho nhu cầu của bạn, có thể đơn giản hơn để gọi 'matcher.find' với'^\ s * ([+ -] *) (\ d +) \ s * ([a-zA-Z ] +) 'nhiều lần, chuyển sang chỉ mục bắt đầu tiếp theo mỗi lần. –

0

Bạn có thể sử dụng ^$ cho rằng, để phù hợp với sự khởi đầu/kết thúc của chuỗi

^\s*(?:([+-]?)(\d+)\s*([a-z]+)\s*)+$ 

https://regex101.com/r/lM7dZ9/2

Xem Unit Tests cho ví dụ của bạn. Về cơ bản, bạn chỉ cần cho phép mẫu lặp lại và buộc rằng không có gì ngoài khoảng trắng xảy ra ở giữa các kết quả khớp.

Kết hợp với kết hợp bắt đầu/kết thúc dòng và bạn đã hoàn tất.

0

Bạn có thể sử dụng String.matches hoặc Matcher.matches trong Java để khớp với toàn bộ khu vực.

Java Ví dụ:

public class RegTest { 

    public static final Pattern PATTERN = Pattern.compile(
      "(\\s*([+-]?)(\\d+)\\s*([a-zA-Z]+)\\s*)+"); 

    @Test 
    public void testDays() throws Exception { 
     assertTrue(valid("1 day")); 
     assertTrue(valid("-1 day")); 
     assertTrue(valid("+1day-1month")); 
     assertTrue(valid("+1day -1month")); 
     assertTrue(valid(" +1day +1month ")); 

     assertFalse(valid("+1day###+1month")); 
     assertFalse(valid("")); 
     assertFalse(valid("++1day-1month")); 
    } 

    private static boolean valid(String s) { 
     return PATTERN.matcher(s).matches(); 
    } 
} 
0

Bạn có thể tiến hành như thế này:

String p = "\\G\\s*(?:([-+]?)(\\d+)\\s*([a-z]+)|\\z)"; 

Pattern RegexCompile = Pattern.compile(p, Pattern.CASE_INSENSITIVE); 

String s = "+1day 1month"; 

ArrayList<HashMap<String, String>> results = new ArrayList<HashMap<String, String>>(); 

Matcher m = RegexCompile.matcher(s); 
boolean validFormat = false;   

while(m.find()) { 
    if (m.group(1) == null) { 
     // if the capture group 1 (or 2 or 3) is null, it means that the second 
     // branch of the pattern has succeeded (the \z branch) and that the end 
     // of the string has been reached. 
     validFormat = true; 
    } else { 
     // otherwise, this is not the end of the string and the match result is 
     // "temporary" stored in the ArrayList 'results' 
     HashMap<String, String> result = new HashMap<String, String>(); 
     result.put("sign", m.group(1)); 
     result.put("multiplier", m.group(2)); 
     result.put("time_unit", m.group(3)); 
     results.add(result); 
    } 
} 

if (validFormat) { 
    for (HashMap item : results) { 
     System.out.println("sign: " + item.get("sign") 
         + "\nmultiplier: " + item.get("multiplier") 
         + "\ntime_unit: " + item.get("time_unit") + "\n"); 
    } 
} else { 
    results.clear(); 
    System.out.println("Invalid Format"); 
} 

Các \G neo phù hợp với sự khởi đầu của chuỗi hoặc vị trí sau khi trận đấu trước đó. Trong mô hình này, nó đảm bảo rằng tất cả các trận đấu đều tiếp giáp. Nếu kết thúc chuỗi được đạt tới, đó là bằng chứng cho thấy chuỗi có giá trị từ đầu đến cuối.

Các vấn đề liên quan