正则表达式验证csv字符串

时间:2015-11-17 12:44:09

标签: java regex validation csv javafx

我在javaFX中有一个TextField,其中背景颜色相应地改变,如果内容有效。

有效:

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

基本上:

  • 仅数字
  • 第一组4或9位
  • 如果第一组9位数 - >总共只有两组
  • 如果第一组4位数 - >总共三,四,五组
  • 第2组和第3组1-9999
  • 第4组和第5组0-9999

现在将其中一条(有效)行视为一个“Ident”。

目前的正则表达式是:

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+)";

到目前为止效果很好,但现在我想要包含csv。所以我只能输入一个我以前使用的标识,或者用逗号(,)分隔的多个标识符,但总共不超过五个标识符。

我的尝试:

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

这使我可以输入:

  • 以上所有有效行
  • 0101 9 1,0101 9 2 0101 9 3
  • 0101 9 1,987654321 21,0101 9 3 0101 9 4

如果我输入5个以上的标识,它就会无效。 但是如果我输入无效的身份0101 9 1 1 1 1 1 1 1 1它仍然有效。

有什么建议吗? :)

编辑:这是匹配逻辑:

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");
                    }
                }
            }
        });

5 个答案:

答案 0 :(得分:3)

你的正则表达式中的逗号是可选,这个事实允许“0101 9 1 1 1 1 1 1 1 1 1”被自由解析为两个或多个记录。

要解决此问题,您可以要求它只是一个或几个逗号分隔的:

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

另外,我建议将 base 本身的输入规则更严格,尽管它似乎与问题没有直接关系。

答案 1 :(得分:1)

这是您问题的解决方案。我稍微修改了正则表达式。你的模式也以某种方式使无效语句的最后一个有效,至少对我而言。您遇到的基本问题是,您的正则表达式未被括号括起来。所以你只是将,?\\s添加到最后一个语句而不是完整的正则表达式语句。

这是我提出的一个经过修改的解决方案,似乎可以验证应该做的所有事情。

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());
}

答案 2 :(得分:1)

我相信这个正则表达式可以满足您的所有要求:

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

您可以尝试here

答案 3 :(得分:1)

让我们分解一下:

  • 仅限数字:

    正则表达式必须匹配数字和空格,并使用^$仅匹配

  • 第一组4或9位数:

    直线前进:\d{4}|\d{9}

  • 如果第一组9位 - &gt;总共只有两组

    \d{9}\s\d 9位数组和第二个

  • 如果第一组4位数 - >总共三,四,五组

    \d{4}(\s\d){2,4} 4位数组后跟2到4组

  • 第2组和第3组1-9999

    1-9999 - &gt; [1-9]\d{0,3}

  • 第4组和第5组0-9999

    轻松一个...... \d{1,4}

然后结合一切:

^ # 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

给出了:

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

您可以尝试live here

答案 4 :(得分:1)

尝试

    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);
    }
}