3

I've found a similar question on SO, but nothing I can get my head around. Here's what I need;

6 or more digits, with these characters allowed \s\-\(\)\+

So here's what I have /^[0-9\s\-\(\)\+]{6,}$/

The problem is, I don't want anything other than the number to count towards the 6 or more quantifier. How can I only "count" the digits? It would also been good if I could stop those other allowed characters from being entered adjacently e.g:

0898--234 
+43 34  434

After an hour of reading up and looking at a regex cheat sheet, I'm hoping some kind person can point me in the right direction!

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
Dan
  • 550
  • 4
  • 10
  • 21
  • 1
    You don't need to escape special chars in a char class : `[0-9\s\-\(\)\+]` become `[\d\s()+-]` (You just need to put the dash `-` at the end) – zessx Nov 19 '13 at 15:07
  • Ah, would I only escape them if they were being caught in a group (parenthesis)? Also, why must the dash go at the end? – Dan Nov 19 '13 at 15:30
  • 1
    @Dan A hyphen is one of the few characters that may have a special meaning inside a character class: a range. By putting it at the end, it can't be denoting a range so it has no special meaning (i.e., it's treated literally) and needs no escaping. You don't _have_ to put it at the end, but if you don't, you should escape it to avoid accidentally specifying a range. – Wiseguy Nov 19 '13 at 15:43
  • @Wiseguy - thanks, I should have seen that one coming, but sometimes regular expressions are pretty tough, especially when you don't write them for a few weeks. – Dan Nov 19 '13 at 15:47
  • 1
    @Dan Example to understand possible issues with hyphen and closing bracket : `[0-1]` vs `[01-]` / `[}])]` vs `[]})]`. – zessx Nov 19 '13 at 16:03

3 Answers3

4

You could do something like this:

/^([\s()+-]*[0-9]){6,}[\s()+-]*$/

This will match any number of special characters (whitespace, parentheses, pluses or hyphens) followed by a single decimal digit, repeated 6 or more times, followed by any number of special characters.

Or this if you don't want to match two or more adjacent special characters:

/^([\s()+-]?[0-9]){6,}[\s()+-]?$/
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • Yes, or use `?` to satisfy the "nice to have" desire to disallow repeated non-digit punctuation. – Pointy Nov 19 '13 at 15:06
  • You can use `/^(?:[\s()+-]?[0-9]+){6,}$/` which is shorter, but can cause backtracking. However the performance is directly linked to the string size. – Casimir et Hippolyte Nov 19 '13 at 15:40
1

You can use lookahead:

/^(?=(\D*\d){6,})[0-9\s()+-]{6,}$/
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • The first section is pretty cool. Does that mean "zero or more of anything that's not a digit and then a digit, six times or more"? – Dan Nov 19 '13 at 15:28
  • Yes that' correct. `\D` is for any non-digit and `\d` is for a digit. `(?=(\D*\d){6,})` will make sure there are at least 6 digits in the input. – anubhava Nov 19 '13 at 15:37
  • 1
    Ok, thanks for explaining. I like all the answers and it's very useful to see different ways to achieve the same objective. – Dan Nov 19 '13 at 15:40
0
/^[\s()+-]*(\d[\s()+-]*){6,}$/

This doesn't count the 'cruft'. It allows any number of special characters, followed by six times [a digit followed by any number of special characters].
If you want max. one special character in between digits, use ? instead of *, but I assume you don't care much for more than one special character at the start or at the end, so I'd go with

/^[\s()+-]*(\d[\s()+-]?){6,}[\s()+-]*$/

This matches any number of special characters, followed by 6 or more times [a digit followed by at most one special character], followed by any number of special characters.


Another option would be to strip your special characters from the string first, and then match against 6 or more digits.

var rawInput = "    12  (3) -- 4 -5 ++6";
var strippedInput = rawInput.replace(/[\s()+-]*/g, "");
return new RegExp("^\d{6,}$").test(strippedInput);

Remember that you have a complete programming language at your disposal. I've noticed people tend to decide they need to use regex and then forget about everything else they can do.

SQB
  • 3,926
  • 2
  • 28
  • 49
  • \d[\s()+-]? - I like this. That's because you can match one number, and either 0 or 1 special character because of the question mark, right? – Dan Nov 19 '13 at 15:35
  • Exactly. The questionmark as a quantifier means one or none. So we're matching a digit followed by an optional ('one or none') special character. The complete regex then does this at least six times and allows for more special characters to the left and the right. All answers do something similar. – SQB Nov 20 '13 at 07:00