46

How can I build a regular expression that will match a string of any length containing any characters but which must contain 21 commas?

Community
  • 1
  • 1

9 Answers9

114
/^([^,]*,){21}[^,]*$/

That is:

^     Start of string
(     Start of group
[^,]* Any character except comma, zero or more times
,     A comma
){21} End and repeat the group 21 times
[^,]* Any character except comma, zero or more times again
$     End of string
Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Greg
  • 316,276
  • 54
  • 369
  • 333
13

If you're using a regex variety that supports the Possessive quantifier (e.g. Java), you can do:

^(?:[^,]*+,){21}[^,]*+$

The Possessive quantifier can be better performance than a Greedy quantifier.


Explanation:

(?x)    # enables comments, so this whole block can be used in a regex.
^       # start of string
(?:     # start non-capturing group
[^,]*+  # as many non-commas as possible, but none required
,       # a comma
)       # end non-capturing group
{21}    # 21 of previous entity (i.e. the group)
[^,]*+  # as many non-commas as possible, but none required
$       # end of string
Peter Boughton
  • 110,170
  • 32
  • 120
  • 176
8

Exactly 21 commas:

^([^,]*,){21}[^,]$

At least 21 commas:

^([^,]?,){21}.*$
Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
7

Might be faster and more understandable to iterate through the string, count the number of commas found and then compare it to 21.

zimbu668
  • 1,295
  • 10
  • 12
2
^(?:[^,]*)(?:,[^,]*){21}$
Sir Rippov the Maple
  • 7,491
  • 5
  • 42
  • 52
1

if exactly 21:

/^[^,]*(,[^,]*){21}$/

if at least 21:

/(,[^,]*){21}/

However, I would suggest don't use regex for such simple task. Because it's slow.

kcwu
  • 6,778
  • 4
  • 27
  • 32
0

What language? There's probably a simpler method.

For example...

In CFML, you can just see if ListLen(MyString) is 22

In Java, you can compare MyString.split(',') to 22

etc...

Peter Boughton
  • 110,170
  • 32
  • 120
  • 176
0
var valid = ((" " + input + " ").split(",").length == 22);

or...

var valid = 21 == (function(input){
    var ret = 0;
    for (var i=0; i<input.length; i++)
        if (input.substr(i,1) == ",")
            ret++;
    return ret
})();

Will perform better than...

var valid = (/^([^,]*,){21}[^,]*$/).test(input);
Tracker1
  • 19,103
  • 12
  • 80
  • 106
-11
.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,.*,
John D. Cook
  • 29,517
  • 10
  • 67
  • 94
  • This will match more than 21 commas – Greg May 14 '09 at 12:51
  • 1
    And it's unreadable too! There's a reason {num} syntax exists. – Peter Boughton May 14 '09 at 13:02
  • Agreed, it's unreadable. The {21} syntax is preferable. But it makes the point visibly: just repeat what you want. It also has the advantage of working in old regex environments that don't support the repeat count syntax. – John D. Cook May 14 '09 at 15:03
  • 4
    It's also extremely inefficient. The first dot-star will initially consume the whole string, then backtrack just enough to let the following comma match. Then the second dot-star-comma will have nothing to match, so the first one will be forced to backtrack again, and so on. This is a recipe for catastrophic backtracking. http://www.regular-expressions.info/catastrophic.html – Alan Moore May 14 '09 at 23:10