2015-11-17 19 views
8

Tôi có một TextField trong javaFX nơi màu nền thay đổi tương ứng nếu nội dung hợp lệ hay không.Regex xác nhận các chuỗi csv

hợp lệ:

987654321 1 
987654321 21 
0101 9 1 
1701 91 1 2 
4101 917 1 0 43 
0801 9 178 2 0 
0111 9 1 084 0 

không hợp lệ:

0101 9 1 0 1 0 
3124 
0314 9 

Về cơ bản:

  • Chỉ số
  • Đầu tiên nhóm 4 hoặc 9 chữ số
  • Nếu nhóm đầu tiên 9 chữ số - > chỉ có hai nhóm trong tổng
  • Nếu nhóm đầu tiên 4 chữ số -> ba, bốn hoặc năm nhóm trong tổng
  • Nhóm hai và ba chữ số 1-9999
  • Nhóm bốn và năm chữ số 0-9999

Bây giờ hãy nghĩ rằng một trong những dòng (hợp lệ) này là một dòng "Ident".

Các regex hiện nay là:

final String base = "(\\d+\\s+\\d+)|(\\d+\\s+\\d+\\s+\\d+(\\s+\\d+)?(\\s+\\d+)?)|(\\d+\\s+\\d+\\s+\\d+)|(\\d+\\s+\\d+\\s+\\d+\\s+\\d+)|(\\d+\\s+\\d+\\s+\\d+\\s+\\d+\\s+\\d+)"; 

Mà hoạt động tuyệt vời cho đến nay, nhưng bây giờ tôi muốn bao gồm csv. Vì vậy, tôi chỉ có thể nhập một định danh như tôi đã từng sử dụng hoặc nhiều id được phân tách bằng dấu phẩy (,), nhưng không quá năm id trong tổng số.

nỗ lực của tôi:

final String pattern = String.format("(%s,?\\s*){1,5}",base); 

Điều này cho phép tôi để đầu vào này:

  • Tất cả các dòng có giá trị trên
  • 0101 9 1, 0101 9 2, 0101 9 3
  • 0101 9 1, 987654321 21, 0101 9 3, 0101 9 4

Và nếu tôi nhập hơn 5 id thì nó sẽ không đúng. Nhưng nếu tôi nhập số nhận dạng không hợp lệ 0101 9 1 1 1 1 1 1 1 1 1 thì nó vẫn hợp lệ.

Mọi đề xuất? :)

EDIT: Đây là logic phù hợp:

private final Predicate<String> typingPredicate = new Predicate<String>() { 
     @Override 
     public boolean apply(String input) { 
      return input.matches(pattern); 
     } 
    }; 
textField.textProperty().addListener(new ChangeListener<String>() { 
      @Override 
      public void changed(ObservableValue<? extends String> observableValue, String previous, String current) { 
       if (current != null) { 
        if (StringUtils.isEmpty(current) || typingPredicate.apply(current.trim())) { 
         textField.getStyleClass().removeAll("invalid"); 
        } else { 
         textField.getStyleClass().add("invalid"); 
        } 
       } 
      } 
     }); 
+0

Tôi đang sử dụng com.google.common.base.Predicate cho phù hợp. Updatet câu hỏi của tôi với logic phù hợp. –

+0

Tại sao không: (i) tách văn bản trên dấu phẩy (ii) kiểm tra xem mỗi mã định danh có hợp lệ với regex gốc của bạn và số lượng idents nhỏ hơn 6? – assylias

+0

Sry, hai nhóm cuối cùng có thể có 0, updatet post. –

Trả lời

3

Dấu phẩy trong cụm từ của bạn là tùy chọn thực tế đó cho phép "tự do phân tích cú pháp thành hai hoặc nhiều bản ghi." 0101 9 1 1 1 1 1 1 1 1 1

Để khắc phục điều này, bạn có thể yêu cầu nó để có chính xác một ident hoặc nhiều phần bằng dấu phẩy:

final String pattern = String.format("(%s\\s*,\\s*){0,4}%s",base,base); 

Ngoài ra tôi muốn giới thiệu để làm cơ sở tự nghiêm ngặt hơn đối với các quy tắc đầu vào của bạn , mặc dù nó dường như không liên quan trực tiếp đến vấn đề này.

+0

Cảm ơn bạn, đó là tất cả những gì tôi cần! :) –

1

Here's một giải pháp cho vấn đề của bạn. Tôi sửa đổi regex một chút. Mẫu của bạn cũng bằng cách nào đó đã làm cho tuyên bố không hợp lệ cuối cùng hợp lệ, ít nhất là đối với tôi. Các vấn đề cơ bản mà bạn đang chạy vào là, regex của bạn không được bao quanh bởi dấu ngoặc đơn. Vì vậy, bạn chỉ thêm ,?\\s vào câu lệnh cuối cùng chứ không phải câu lệnh regex hoàn chỉnh.

Dưới đây là giải pháp sửa đổi mà tôi đã đưa ra, có vẻ như xác thực mọi thứ như nó sẽ làm.

public static void main(String[] args) { 
    String[] inputs = {"987654321 1", 
         "987654321 21", 
         "0101 9 1", 
         "1701 91 1 2", 
         "4101 917 1 0 43", 
         "0801 9 178 2 0", 
         "0111 9 1 084 0", 
         "0101 9 1 0 1 0", 
         "3124", 
         "0314 9"}; 
    String regex = "(((\\d{9}(\\s\\d*)))|(\\d{4}(\\s[1-9]\\d{0,3}){2}(\\s\\d{1,4}){0,2}))"; 
    String csvRegex = "("+ regex + ",\\s){0,4}"+regex; 
    for(String s : inputs) { 
     Matcher m = Pattern.compile(csvRegex).matcher(s); 
     System.out.println(m.matches()); 
    } 

    String falseCSVString = "987654321 1, 987654321 21, 1701 91 1 2, 0111 9 1 084 0, 0101 9 1 1 1 1 1 1 1 1 1"; 
    Matcher m = Pattern.compile(csvRegex).matcher(falseCSVString); 
    System.out.println(m.matches()); 

    String rightCSVString = "987654321 1, 987654321 21, 1701 91 1 2, 0111 9 1 084 0, 0101 9 1"; 
    m = Pattern.compile(csvRegex).matcher(rightCSVString); 
    System.out.println(m.matches()); 
} 
+0

Tôi nhận thấy rằng số thứ hai của bạn trong trường hợp số đầu tiên gồm 9 chữ số không tuân theo quy tắc "số 1-9999", tôi không chắc liệu nó có chỉ áp dụng cho các số sau số đầu tiên gồm 4 chữ số hay không . – Aaron

+0

@Aaron tôi không, nhưng tôi nghĩ rằng nó sẽ là trường hợp. Tôi đoán OP sẽ nói điều gì đó. – SomeJavaGuy

1

Tôi tin rằng đây regex trả lời tất cả các yêu cầu của bạn:

^\d{9} [1-9]\d{0,3}$|^\d{4}(?: [1-9]\d{0,3}){2}(?: \d{1,4}){0,2}$ 

Bạn có thể thử nó here.

+0

Không cho '987654321 11111111111' làm' $ 'của bạn chỉ khớp với trường hợp thứ hai (nhóm 4 chữ số) – Cyrbil

+0

@Cyrbil cảm ơn, đã sửa nó. – Aaron

1

Hãy phá vỡ mọi thứ xuống:

  • Chỉ số:

    Các regex sẽ phải phù hợp với chữ số và không gian và sử dụng ^$ để phù hợp duy nhất mà

  • nhóm đầu tiên 4 hoặc 9 chữ số :

    Dây đeo về phía trước: \d{4}|\d{9}

  • Nếu nhóm đầu tiên 9 chữ số -> chỉ có hai nhóm trong tổng

    \d{9}\s\d nhóm 9 chữ số và thứ hai

  • Nếu lần đầu tiên nhóm 4 chữ số -> ba, bốn hoặc năm nhóm trong tổng

    \d{4}(\s\d){2,4} nhóm 4 chữ số tiếp theo 2-4 nhóm

  • nhóm hai và ba chữ số 1-9999

    1-9999 ->[1-9]\d{0,3}

  • Nhóm bốn và năm chữ số 0-9999

    dễ dàng một ...\d{1,4}

Sau đó, kết hợp tất cả mọi thứ:

^ # match start of string 
    (\d{4} # group start with 4 digits 
    (\s[1-9]\d{0,3}){2} # group of 1-9999 twice 
    (\s\d{1,4}){0,2} # group of 0-9999 zero to two times 
)|(\d{9} # group start with 9 digits 
    \s[1-9]\d{0,3} # group of 1-9999 
)$ # end of string match 

Mà cho:

^((\d{4}(\s[1-9]\d{0,3}){2}(\s\d{1,4}){0,2})|(\d{9}\s[1-9]\d{0,3}))$ 

Bạn có thể thử nó live here

1

Hãy thử

String ident = "\\s*(([0-9]{9}\\s+[1-9][0-9]{0,3})|(\\d{4}(\\s+[1-9]\\d{0,3}){2}(\\s+\\d{1,4}){2}))\\s*"; 

    String regex = String.format("\\A%s(,%s){0,4}\\z", ident, ident); 

SSCCE:

import java.util.regex.Pattern; 

import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.binding.BooleanBinding; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class ValidatingTextFieldExample extends Application { 

    private BooleanBinding valid ; 

    @Override 
    public void start(Stage primaryStage) { 
     String ident = "\\s*(([0-9]{9}\\s+[1-9][0-9]{0,3})|(\\d{4}(\\s+[1-9]\\d{0,3}){2}(\\s+\\d{1,4}){2}))\\s*"; 

     String regex = String.format("\\A%s(,%s)*\\z", ident, ident); 

     Pattern pattern = Pattern.compile(regex); 

     TextField textField = new TextField(); 
     String INVALID_STYLE = "-fx-background-color: red;" ; 
     textField.setStyle(INVALID_STYLE); 

     valid = Bindings.createBooleanBinding(() -> 
      pattern.matcher(textField.getText()).matches(), 
      textField.textProperty()); 

     valid.addListener((obs, wasValid, isValid) -> { 
      if (isValid) { 
       textField.setStyle(""); 
      } else { 
       textField.setStyle(INVALID_STYLE); 
      } 
     }); 

     StackPane root = new StackPane(textField); 
     primaryStage.setScene(new Scene(root, 350, 120)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
Các vấn đề liên quan