Reputation: 23
I am stuck with a regex function. It's been quite fun developing it to get it to the point it's at now, but I can't seem to improve it any further, even using other examples online.
I have the following regex function which I'm using to detect 16 digit card numbers,
(?<=^|[^0-9])[0-9]{16}(?=[^0-9]|$)|[0-9]{4}[-| |_][0-9]{4}[-| |_][0-9]{4}[-| |_][0-9]{4}
This function detects the following results,
1) 1234123412341234 (16 digits all together)
2) 1234 1234 1234 1234
3) 1234-1234-1234-1234 (card numbers with hyphens and spaces)
4) Find me 1234-1234-1234-1234 Find me (card numbers hidden amongst text)
What I'm struggling to stop is the false positives I get, which I know are a direct result of achieving result number 4 above. The false positives being more than 16 digits which are clearly not card numbers. E.g
1) 1234-1234-1234-1234-1234
As it detects the first 16 digits in the string the regex returns the value. I have created a procedure which filters out these false positives, but I thought it was worth seeing if someone can improve the above, so others can use the regex function. As other examples on the internet didn't seem to do the job for me.
Upvotes: 2
Views: 3653
Reputation: 626903
You may use
(?<!\d)\d{16}(?!\d)|(?<!\d[ _-])(?<!\d)\d{4}(?:[_ -]\d{4}){3}(?![_ -]?\d)
See this regex demo.
Or, if the delimiters between groups must be the same,
(?<!\d)\d{16}(?!\d)|(?<!\d[ _-])(?<!\d)\d{4}(?=([_ -]))(?:\1\d{4}){3}(?![_ -]?\d)
Or, unrolled (without the positive lookahead):
(?<!\d)\d{16}(?!\d)|(?<!\d[ _-])(?<!\d)\d{4}([_ -])\d{4}(?:\1\d{4}){2}(?![_ -]?\d)
See this regex demo.
Details
(?<!\d)\d{16}(?!\d)
- sixteen digits not enclosed with any other digit|
- or(?<!\d[ _-])(?<!\d)
- a location not immediately preceded with a digit or a digit and space/_
/-
\d{4}
- four digits(?:[_ -]\d{4}){3}
- three repetitions of a _
, space or -
and then any four digits(?![_ -]?\d)
- a location not immediately followed with an optional _
/ space or -
and then a digit.Upvotes: 2
Reputation: 1041
I'd simplify the whole regex to \s((\d{4}[\s-]?){3}\d{4})\s
.
The difference is that I'm asking for 3 groups of 4 digits plus an optional separator, then another group of 4 digits. That way, I'm sure to have always 16. The \s
help delimiting the candidate, you may not need that.
Test on https://regex101.com/
Upvotes: 0