Reputation: 80
I'm using a regex, to validate some stuff in my angular2 application:
Validators.pattern('\d*F{1}N{1}K?J?')
I just want to allow digits (0-9) and the letters F N K J. K and J should be optional, F and N have to be in there exactly one time.
Does anyone know, how to ignore the order of letters and digits? Not it just matches, if I exactly insert chars in this order: 012FNKJ. KJFN012 doesn't match at all. :(
Upvotes: 1
Views: 5606
Reputation: 18279
Here is a suggestion. It matches "any string of K
, J
and digits
that contains exactly one F
and exactly one N
".
^[KJ0-9]*F[KJ0-9]*N[KJ0-9]*$
Explanation:
[KJ0-9]*
between zero and unlimited times K, J and numbersF[KJ0-9]*
a F followed by K, J and numbersN[KJ0-9]*
a N followed by K, J and numbersNote that if N
can be before F
in your pattern, you may want to use
^[KJ0-9]*F[KJ0-9]*N[KJ0-9]*|[KJ0-9]*N[KJ0-9]*F[KJ0-9]*$
As you can not make a regex count basically, that is the cleaner way I see to check it with a regex.
Upvotes: 0
Reputation: 8332
You can use a negative look-ahead combined with a back reference:
^(?=.*F)(?=.*N)(?:\d|([FNKJ])(?!.*\1))*$
It starts by using look-aheads to make sure the F
and the N
are in there.Then it matches digits, or a letter from the allowed group capturing the letter followed by a negative look-ahead to ensure it doesn't repeat itself. The previous alternative is then repeated, until the end of the string.
Upvotes: 2
Reputation: 8833
You need to use |
to say "this pattern or this pattern", and explicitly lay out both patterns.
[0-9KJ]*F[0-9KJ]*N[0-9KJ]*|[0-9KJ]*N[0-9KJ]*F[0-9KJ]*
This is why Regex is not good for fuzzy matching. You'd be better validating with [0-9FNKJ]*
and string.containsOne('F', 'N')
(psudo code)
Upvotes: 0
Reputation: 28285
Here is a pure regex answer to your problem (whitespace has been added for improved readability):
^
(?=[^F]*F[^F]*$)
(?=[^N]*N[^N]*$)
(?=[^K]*K?[^K]*$)
(?=[^J]*J?[^J]*$)
[FNKJ\d]+$
Explanation:
(?=...)
sections of the pattern are lookaheads. They are saying, for example, "the string must contain any number of non-K
s, then maybe one K
, then any number more non-K
s".F
, N
, K
, J
and digits".However, if possible then I would recommend implementing a non-regex solution to this problem. My answer above is difficult to understand, and way slower than a simple function could be (O(n)
!).
Some pseudo-code that solves this without a regex, in O(n)
:
function check_valid(string) {
found_f = false
found_n = false
found_k = false
found_j = false
for(letter in string) {
switch(letter) {
case 'F':
if(found_f) { return false }
found_f = true
break;
case 'N':
if(found_n) { return false }
found_n = true
break;
case 'K':
if(found_k) { return false }
found_k = true
break;
case 'J':
if(found_j) { return false }
found_j = true
break;
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
break;
default:
return false;
}
}
return(found_f & found_n)
}
Upvotes: 3