Regex checks csv strings

I have a TextField in javaFX where the background color changes accordingly if the content is valid or not.

Really:

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 

Invalid:

 0101 9 1 0 1 0 3124 0314 9 

Mostly:

  • Only numbers
  • First group of 4 or 9 digits
  • If the first group is 9 digits โ†’ just two groups in total
  • If the first group is 4 digits โ†’ three, four or five groups in total
  • Group two and three digits 1-9999
  • Group four and five digits 0-9999

Now think of one of these (valid) lines as "Identity."

Current current regex:

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

Wich works fine so far, but now I want to enable csv. Therefore, I can enter only one identifier, as I'm used to, or several identifiers, separated by a comma (,), but not more than five identifiers.

My attempt:

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

This allows me to enter this:

  • All valid lines above
  • 0101 9 1, 0101 9 2, 0101 9 3
  • 0101 9 1, 987654321 21, 0101 9 3, 0101 9 4

And if I enter more than 5 identities, it is incorrectly correct. But if I enter the wrong identifier 0101 9 1 1 1 1 1 1 1 1 1, it will still become valid.

Any suggestions?:)

EDIT: This is the correspondence logic:

 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"); } } } }); 
+8
java regex validation javafx csv
source share
5 answers

A comma in your regular expression is optional , which allows "0101 9 1 1 1 1 1 1 1 1 1 1" to be freely parsed as two or more entries.

To fix this, you can require from it either exactly one identifier, or several separated by commas:

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

I would also recommend making the framework stricter regarding your input rules, although it does not seem to be directly related to the problem.

+3
source share

Here is the solution to your problem. I changed the regex a bit. Your model also somehow made the last invalid statement valid, at least for me. The main problem you are facing is that your regular expression is not surrounded by parentheses. So you add ,?\\s to the last statement, and not to the full regex expression.

Here is a modified solution that I came across that seems to check everything as it should.

 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()); } 
+1
source share

I believe this regex meets all your requirements:

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

You can try it here .

+1
source share

Let the things break:

  • Only numbers:

    The regular expression will have to match numbers and spaces and use ^$ to match just that

  • The first group is 4 or 9 digits:

    Straight ahead: \d{4}|\d{9}

  • If the first group is 9 digits โ†’ only two groups in total

    \d{9}\s\d group of 9 digits and a second

  • If the first group is 4 digits โ†’ three, four or five groups in total

    \d{4}(\s\d){2,4} 4-digit group followed by 2 to 4 groups

  • Group two and three digits 1-9999

    1-9999 โ†’ [1-9]\d{0,3}

  • Group four and five digits 0-9999

    Easy ... \d{1,4}

Then combine everything:

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

What gives:

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

You can try living here

+1
source share

Try

  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); } } 
+1
source share

All Articles