Regex for Discover credit card - regex

I have read through this question, but for Discover card, the starting digits are 6011, 622126-622925, 644-649, 65 instead of just 6011, 65. (Source)
For Discover cards, I picked up this regex from that question ^6(?:011|5[0-9]{2})[0-9]{12}$
I modified it to cover 6011, 644-649& 65 but for 622126-622925, building regex is hard cuz of my poor regex skills.
I have this regex so far 6(?:011|5[0-9]{2}|[4][4-9][0-9]|[2]{2}[1-9])[0-9]{2}$, but it only checks for 622[1-9]**.
How do I modify it so that it accepts only between 622126-622925 for 622*** case?

Here's your regex (demo):
^6(?:011\d{12}|5\d{14}|4[4-9]\d{13}|22(?:1(?:2[6-9]|[3-9]\d)|[2-8]\d{2}|9(?:[01]\d|2[0-5]))\d{10})$
Needless to say, I won't exactly call this pretty or easy to maintain. I would recommend parsing the number as an integer and using your programming language to do the checks.
You should also use Luhn algorithm to check if the credit card number is valid, and while you could theoretically do this with regex, it would many times worse than this.
Allow me to show you how I arrived at this monstrosity, step by step. First, here is how you match each of those ranges:
6011 # matches 6011
65 # matches 65
64[4-9] # matches 644-649
622(1(2[6-9]|[3-9]\d)|[2-8]\d{2}|9([01]\d|2[0-5]))
# matches 622126-622925
Now, you want to match the rest of the digits:
6011\d{12} # matches 6011 + 12 digits
65\d{14} # matches 65 + 14 digits
64[4-9]\d{13} # matches 644-649 + 13 digits
622(1(2[6-9]|[3-9]\d)|[2-8]\d{2}|9([01]\d|2[0-5]))\d{10}
# matches 622126-622925 + 10 digits
Now you can combine all four, and add start and end of line anchors:
^( # match start of string and open group
6011\d{12}| # matches 6011 + 12 digits
65\d{14}| # matches 65 + 14 digits
64[4-9]\d{13}| # matches 644-649 + 13 digits
622(1(2[6-9]|[3-9]\d)|[2-8]\d{2}|9([01]\d|2[0-5]))\d{10}
# matches 622126-622925 + 10 digits
)$ # close group and match end of string
The final product above is a slightly compacted version of the previous regex, and I also made groups non-capturing (that's what those ?: are for).

Here are your options:
Hack your way through it and build a really complicated regex. Regexes are not suited for this sort of integer comparison so what you come up with will necessarily be long, uncomplicated and unmaintainable. See Regex for number check below a value and similar SO questions on this topic.
Use integer comparison in your code.
For reference one such said complicated regex would be
62212[6-9]|6221[3-9]|622[1-8]|62291|62292[1-5]

even this ticket is 3 years ago, I encountered the same task and would like to share a regex for 622126-622925 :)
^(622[1-9]\\d(?<!10|11|9[3-9])\\d(?<!12[0-5]|92[6-9])\\d{10})$
which using zero-width negative lookbehind to exclude not expected number

Related

Regex for alphanumeric string including at least one digit

I'm looking for a regex with at the conditions:
a) minimum 13 alphanumeric characters
b) maximum 17 alphanumeric
characters
c) and at least 1 digit.
This regex fulfils a) and b). How can it fulfil also condition c)?
^[a-zA-Z0-9]{13,17}$
Example input texts:
# matching
123456789abcd
123456789abcdef
123456789abcdefg
# no match: too long
123456789abcdefgef
# no match: no digit
abcdefghijklmno
# no match: not alphanumeric only
123456789#abcdefg
The flavor is Java 8.
It sounds like you are trying to make a password checker. I suggest that you NOT try to do it all in one single regex.
Check your input against two different regexes that must both match:
^[a-zA-Z0-9]{13,17}$ # 13-17 alphanumerics
and
[0-9] # at least one digit
Compared to this suggestion from another answer...
^(?=[a-zA-Z]*[0-9])(?=[0-9]*[a-zA-Z])[[:alnum:]]{13,17}$
... it's so much clearer that way, and easier to change when your rules change in the future.
Regex:
^(?=[a-zA-Z]*[0-9])(?=[0-9]*[a-zA-Z])[[:alnum:]]{13,17}$
Explanation:
^(?=[a-zA-Z]*[0-9]) - Lookahead for zero or more letters followed by a number, somewhere in the string, note this is faster than the (?=.*[0-9]) suggested in another answer.
(?=[0-9]*[a-zA-Z]) - as above but looking for at least one letter (I assume you want this, although it wasn't specified in your answer.
[[:alnum:]]{13,17}$ - The actual match bit; this is just your regex ([a-zA-Z0-9]{13,17}$) in short-hand.
If it's more likely that a string will not have a letter then swapping the order of the lookaheads should make it faster. The current order would be best if a missing number is the most likely fail condition (as the regex will fail faster).
See https://www.rexegg.com/regex-lookarounds.html#password for a detailed explanation.
Regex Tests

Google sheets formula to extract 10-digit mobile number starting from 69

I want to extract the mobile phones from candidates' CVs.
The mobile phone format I want to extract is 69xxxxxxxx.
The mobile phone formats i come across in the CVs are:
69 xxx xxxxx
0030 69xxxxxxxx
+3069xxxxxxxx
69/xxxx/xxxx
The following formula works great but it extracts the first 10 digits detected and not the one that starts with 69.
=IFERROR(REGEXEXTRACT(TO_TEXT(SPLIT(REGEXREPLACE(I252;"\(|\)|\-| "; ""); CHAR(10))); "\d{10}"))
You may use
=IFERROR(REGEXEXTRACT(TO_TEXT(SPLIT(REGEXREPLACE(I252;"[-/() ]+"; ""); CHAR(10))); "(?:\+|00)?(?:30)?(69\d{8})"))
See the regex demo and the Google Sheets screenshot below:
The regex matches
(?:\+|00)? - an optional + or 00
(?:30)? - an optional 30
( - start of the capturing group (only this value will be returned):
69 - 69 value
\d{8} - eight digits
) - end of the group.
You might consider appending \b at the end of the regex to avoid matching the 8 digits in chunks of more than 8 digits.
Note that the separator cleaning regex is [-/() ]+ now, it matches 1 or more -, /, (, ) and spaces.
The solution to your problem is to make use of a regex lookbehind (although I do not know if Google Sheets supports this).
A regex lookbehind matches a pattern, but without including in the result. The syntax for this, with your example, is:
(?<=69)\d{10}
The picture below is taken from https://regex101.com/ (which is a super-useful tool when working with regexps).
Regex lookahead, lookbehind and atomic groups has some more examples of how lookaheads and lookbehinds work.
all you need is:
=ARRAYFORMULA(IFNA(REGEXREPLACE(REGEXEXTRACT(A1:A&""; "69.*"); "\s|/|\D+"; )))
or better:
=ARRAYFORMULA(IFNA(REGEXEXTRACT(REGEXREPLACE(A1:A&""; "\D+"; ); "69.{8}")))

Regex to match less than a two-digit number

I have some records as such, in a file:
A 20 year old programmer
A 52 year old politician
A 12 year old practitioner
Many many more of these...
I want to match only lines that contain a number less than 20. I have tried:
^[0-20]{2}$
But it works for only numbers 0-2. How should I construct a regular expression to match numbers < 20? For instance, it should match:
A 12 year old practitioner
But not
A 20 year old programmer
A 52 year old politician
You may use
\b1?[0-9]\b
See the regex demo
Details
\b - a word boundary
(?:1?[0-9]) - an optional 1 and any digit after it
\b - a word boundary
Word boundary variations
To match anywhere in a string, even if glued to a word:
(?<!\d)1?[0-9](?!\d)
To only match in between whitespaces:
(?<!\S)1?[0-9](?!\S)
Using regex to match digit ranges is usually a bit clumsy, but here, you can do it pretty simply with:
\b1?\d\b
https://regex101.com/r/YCWmNo/2
In plain language: an optional one, followed by a digit. So, any standalone digit is allowed, but a two-digit number needs its first digit to be a 1.
If you want to permit leading zeros, change to \b[01]?\d\b.

Regex is possible to match?

I have files with these filename:
ZATR0008_2018.pdf
ZATR0018_2018.pdf
ZATR0218_2018.pdf
Where the 4 digits after ZATR is the issue number of magazine.
With this regex:
([1-9][0-9]*)(?=_\d)
I can extract 8, 18 or 218 but I would like to keep minimum 2 digits and max 3 digits so the result should be 08, 18 and 218.
How is possible to do that?
You may use
0*(\d{2,3})_\d
and grab Group 1 value. See the regex demo.
Details
0* - zero or more 0 chars
(\d{2,3}) - Group 1: two or three digits
_\d - a _ followed with a digit.
Here is a PCRE variation that grabs the value you need into a whole match:
0*\K\d{2,3}(?=_\d)
See another regex demo
Here, \K makes the regex engine omit the text matched so far (zeros) and then matches 2 to 3 digits that are followed with _ and a digit.
(?:[1-9][0-9]?)?[0-9]{2}(?=_[0-9])
or perhaps:
(?:[1-9][0-9]+|[0-9]{2})(?=_[0-9])
(https://www.freeformatter.com/regex-tester.html, which claims to use the XRegExp library, that you mention in another answer doesn't seem to backtrack into the (?:)? in my first suggestion where necessary, which makes it very different from any regex engine I've encoutered before and makes it prefer to match just the 18 of 218 even though it starts later in the string. But it does work with my second suggestion.
([1-9]\d{2,3})(?=_\d)
{x,y} will match from x to y times the previous pattern, in this case \d
Edit: from your own regex it looked as you wanted the part of the number which starts with a non-zero. However since your examples include leading 0s, maybe you really wanted :
(\d{2,3})(?=_\d)
Which will give you the last 3 digits before underscore unless there are only 2 digits.
I propose you:
^ZATR0*(\d{2,3})_\d+\.pdf$
demo code here. Result:
Match 1 Full match 0-17 ZATR0008_2018.pdf Group 1. 6-8 08
Match 2 Full match 18-35 ZATR0018_2018.pdf Group 1. 24-26 18
Match 3 Full match 36-53 ZATR0218_2018.pdf Group 1. 41-44 218

Validation of international telephone numbers with REGEXMATCH

I'm trying to apply a data validation formula to a column, checking if the content is a valid international telephone number. The problem is I can't have +1 or +some dial code because it's interpreted as an operator. So I'm looking for a regex that accepts all these, with the dial code in parentheses:
(+1)-234-567-8901
(+61)-234-567-89-01
(+46)-234 5678901
(+1) (234) 56 89 901
(+1) (234) 56-89 901
(+46).234.567.8901
(+1)/234/567/8901
A starting regex can be this one (where I also took the examples).
This regex match all the example you gave us (tested with https://fr.functions-online.com/preg_match_all.html)
/^\(\+\d+\)[\/\. \-]\(?\d{3}\)?[\/\. \-][\d\- \.\/]{7,11}$/m
^ Match the beginning of the string or new line.
To match (+1) and (+61): \(\+\d+\): The plus sign and the parentheses have to be escaped since they have special meaning in the regex. \d+ Stand for any digit (\d) character and the plus means one or more (the plus could be replaced by {1,2})
[\/\. \-] This match dot, space, slash and hyphen exactly one time.
\(?\d{3}\)?: The question mark is for optional parenthesis (? = 0 or 1 time). It expect three digits.
[\/\. \-] Same as step 3
[\d\- \.\/]{7,11}: Expect digits, hyphen, space, dot or slash between 7 and 11 time.
$ Match the end of the line or the end of the string
The m modifier allow the caret (^) and dollar sign ($) combination to match line break. Remove that if you want those symbol to match only the begining and the end of the string.
Slashes are use are delimiter for this regex (there are other character that you can use).
I must admit I don't like the last part of the regex as do not ensure that you have at least 7 digits.
It would be probably better to remove all the separator (by example with PHP function str_replace) and deal only with parenthesis and number with this regex
/(\(\+\d+\))(\(?\d{3}\)?)(\d{3})(\d{4})/m
Notice that in this last regex I used 4 capturing group to match the four digit section of the phone number. This regex keep the parenthesis and the plus sign of the first group and the optional parenthesis of the second group. To keep only the digits group, you can use this regex:
/\(\+(\d+)\)\(?(\d{3})\)?(\d{3})(\d{4})/m
Note: The groups are for formatting the phone number after validating it. It is probably better for you to keep all your phone number in your database in the same format.
Well, here are different possibility you can use.
Note: Those regex should be compatible with all regex engine, but it is good practice to specify with which language you works because regex engine don't deal the same way with advanced/fancy function.
By example, the look behind is not supported by javascript and .Net allow a more powerful control on lookbehind than PHP.
Keep me in touch if you need more information