Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RegEx for matching X digits with one optional comma in between digits?

Tags:

java

regex

I'm trying to write a RegExp to match only 8 digits, with one optional comma maybe hidden in-between the digits.

All of these should match:

12345678
12,45678
123456,8

Right now I have:

^[0-9,]{8}

but of course that erroneously matches 012,,,67

Example: https://regex101.com/r/dX9aS9/1

I know optionals exist but don't understand how to keep the 8 digit length applying to the comma while also keeping the comma limited to 1.

Any tips would be appreciated, thanks!

like image 837
Javed Ahamed Avatar asked Apr 07 '16 18:04

Javed Ahamed


3 Answers

To match 8 char string that can only contain digits and an optional comma in-between, you may use

^(?=.{8}$)\d+,?\d+$

See the regex demo

The lookahead will require the string to contain 8 chars. ,? will make matching a comma optional, and the + after \d will require at least 1 digit before and after an optional comma.

If you need to match a string that has 8 digits and an optional comma, you can use

^(?:(?=.{9}$)\d+,\d+|\d{8})$

See the regex demo

Actually, the string will have 9 characters in the string (if it has a comma), or just 8 - if there are only digits.

Explanation:

  • ^ - start of string
  • (?:(?=.{9}$)\d+,\d+|\d{8}) - 2 alternatives:
    • (?=.{9}$)\d+,\d+ - 1+ digits followed with 1 comma followed with 1+ digits, and the whole string matched should be 9 char long (8 digits and 1 comma)
    • | - or
    • \d{8} - 8 digits
  • $ - end of string

See the Java code demo (note that with String#matches(), the ^ and $ anchors at the start and end of the pattern are redundant and can be omitted since the pattern is anchored by default when used with this method):

List<String> strs = Arrays.asList("0123,,678", "0123456", // bad
        "01234,567", "01234567" // good
    );
for (String str : strs)
    System.out.println(str.matches("(?:(?=.{9}$)\\d+,\\d+|\\d{8})"));

NOTE FOR LEADING/TRAILING COMMAS:

You just need to replace + (match 1 or more occurrences) quantifiers to * (match 0 or more occurrences) in the first alternative branch to allow leading/trailing commas:

^(?:(?=.{9}$)\d*,\d*|\d{8})$

See this regex demo

like image 53
Wiktor Stribiżew Avatar answered Oct 28 '22 15:10

Wiktor Stribiżew


You can use following regex if you want to let trailing comma:

^((\d,?){8})$

Demo

Otherwise use following one:

^((\d,?){8})(?<!,)$

Demo

(?<!,) is a negative-lookbehind.

like image 2
Mazdak Avatar answered Oct 28 '22 17:10

Mazdak


/^(?!\d{0,6},\d{0,6},\d{0,6})(?=\d[\d,]{6}\d).{8}$/

I guess this cooperation of positive and negative look-ahead does just what's asked. If you remove the start and end delimiters and set the g flag then it will try to match the pattern along decimal strings longer than 8 characters as well.

Please try http://regexr.com/3d63m

Explanation: The negative look ahead (?!\d{0,6},\d{0,6},\d{0,6}) tries not to find any commas side by side if they have 6 or less decimal characters in between while the positive look ahead (?=\d[\d,]{6}\d) tries to find 6 decimal or comma characters in between two decimal characters. And the last .{8} selects 8 characters.

like image 1
Redu Avatar answered Oct 28 '22 16:10

Redu