Regex Visa + Mastercard with Spaces need Add Amex - regex

I have this Regex to validate Visa and Master card with spaces, it works perfect.
^(?:4\d{3}|5[1-5]\d{2}|6011|3[47]\d{2})([- ]?)\d{4}\1\d{4}\1\d{4}$
Visa
4111111111111111 = true
4111 1111 1111 1111 = true
Master
5500000000000004 = true
5500 0000 0000 0004 = true
American Express
340000000000009 = false
3400 0000 0000 009 = false
I need add Amex to the regex, I need the last two true, can anyone help me please?
Thank you!

(assuming 4111111111111111 = false is a typo)
You can use the following regex :
^(?:4\d{3}|5[1-5]\d{2}|6011|3[47]\d{2})([-\s]?)\d{4}\1\d{4}\1\d{3,4}$
see demo

I do not know the background how you use this regex but i would do this in two steps:
Step 1:
Remove all spaces with one line of code. Since spacing should not define whether a number is valid/invalid.
Step 2:
Use this regex
^(?:4[0-9]{12}(?:[0-9]{3})?|(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}|3[47][0-9]{13})$
This catches a few more rules on MasterCards.
Source (Shortend expression since fewer types of cards are needed)
Demo

Related

Reg Ex is getting more digits than expected

Dont suggest me any links , I saw all million times.
I looked at many suggestions - such as Regex credit card number tests. However, I'm not primarily concerned with verifying potential credit numbers.
I want to locate (potentential) credit card numbers in a document by identifying sequences of 12 to 19 numbers (plus a few common separator characters between them). This is being discussed in, e.g., Finding or Verifying Credit Card Numbers, at which #TimBiegeleisen points. But the suggested solution results in a few false negatives. (See section "Problems..." below.)
Sample input:
[ '232625427',
'please stop check 220 2000000 that was sent 6/10 reg mail and reissu fedex. Please
charge to credit card 4610 0000 0000 0000 exp 05/99...thanks, Sxxx' ]
[ '232653042',
'MARKET PLACE: Exxxx or Bxxxx-Please set husband and wife up on monthly credit card
payments. Name on the credit card is Hxxxx-Jxxxx Lxxxx (Maiden name, name on policy is different) Master card number 5424 0000 0000 0000 Exp 11-30-00. Thanks so much.' ]
Much more sample input at my RegEx101.com attempt.
My regex is
[1-9](\d[ ]?[ ]*?[-]?[-]*?[:]*?[:]?){11,18}\b
Problems with my RegEx
The 12-19 digit numbers are not matched when immediately followed by a string. It fails, e.g., on 4554-4545-4545-4545Visa.
Longer running sequences of numbers are matched at the end rather than the beginning: For 999999999999994190000000000000 I do get 9994190000000000000 instead of 9999999999999941900
I am testing it at RegEx101.com.
To address the problem in your title "Reg Ex is getting more digits than expected" (reading "digits" as "characters", though), try:
[1-9]([- :]*\d){11,18}\b
This way, you no longer match trailing blanks in your sample input. See it in action at RegEx101.com.
Closer to what you pointed out under "Problems..." should be:
[1-9]([- :]*\d){11,18}
With the word boundary removed from the end, strings immediately following the sequence of numbers are no longer causing false negatives. And the match is no longer biased towards the end of a potential match, either. This, however, handles 001 111111111111 differently from your approach:
RegEx101.com.
This could be accounted for with
[1-9][0-9]([- :]*\d){10,17}
at the cost of allowing a few more zeros from "5452 0000 0000 0000000": RegEx101.com.
All suggestions were checked against your sample input, only. Different input might require further tweaking.
Please comment, if and as this requires adjustment / further detail.

IBAN Regex design [duplicate]

This question already has answers here:
IBAN Validation check
(11 answers)
Closed 4 years ago.
Help me please to design Regex that will match all IBANs with all possible whitespaces. Because I've found that one, but it does not work with whitespaces.
[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}
I need at least that formats:
DE89 3704 0044 0532 0130 00
AT61 1904 3002 3457 3201
FR14 2004 1010 0505 0001 3
Just to find the example IBAN's from those countries in a text :
Start with 2 letters then 2 digits.
Then allow a space before every 4 digits, optionally ending with 1 or 2 digits:
\b[A-Z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?!(?:[ ]?[0-9]){3})(?:[ ]?[0-9]{1,2})?\b
regex101 test here
Note that if the intention is to validate a complete string, that the regex can be simplified.
Since the negative look-ahead (?!...) won't be needed then.
And the word boundaries \b can be replaced by the start ^ and end $ of the line.
^[A-Z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?:[ ]?[0-9]{1,2})?$
Also, it can be simplified even more if having the 4 groups of 4 connected digits doesn't really matter.
^[A-Z]{2}(?:[ ]?[0-9]){18,20}$
Extra
If you need to match an IBAN number from accross the world?
Then the BBAN part of the IBAN is allowed to have up to 30 numbers or uppercase letters. Reference
And can be written with either spaces or dashes or nothing in between.
For example: CC12-XXXX-12XX-1234-5678-9012-3456-7890-123
So the regex pattern to match a complete string with a long IBAN becomes a bit longer.
^([A-Z]{2}[ \-]?[0-9]{2})(?=(?:[ \-]?[A-Z0-9]){9,30}$)((?:[ \-]?[A-Z0-9]{3,5}){2,7})([ \-]?[A-Z0-9]{1,3})?$
regex101 test here
Also note, that a pure regex solution can't do calculations.
So to actually validate an IBAN number then extra code is required.
Example Javascript Snippet:
function smellsLikeIban(str){
return /^([A-Z]{2}[ \-]?[0-9]{2})(?=(?:[ \-]?[A-Z0-9]){9,30}$)((?:[ \-]?[A-Z0-9]{3,5}){2,7})([ \-]?[A-Z0-9]{1,3})?$/.test(str);
}
function validateIbanChecksum(iban) {
const ibanStripped = iban.replace(/[^A-Z0-9]+/gi,'') //keep numbers and letters only
.toUpperCase(); //calculation expects upper-case
const m = ibanStripped.match(/^([A-Z]{2})([0-9]{2})([A-Z0-9]{9,30})$/);
if(!m) return false;
const numbericed = (m[3] + m[1] + m[2]).replace(/[A-Z]/g,function(ch){
//replace upper-case characters by numbers 10 to 35
return (ch.charCodeAt(0)-55);
});
//The resulting number would be to long for javascript to handle without loosing precision.
//So the trick is to chop the string up in smaller parts.
const mod97 = numbericed.match(/\d{1,7}/g)
.reduce(function(total, curr){ return Number(total + curr)%97},'');
return (mod97 === 1);
};
var arr = [
'DE89 3704 0044 0532 0130 00', // ok
'AT61 1904 3002 3457 3201', // ok
'FR14 2004 1010 0505 0001 3', // wrong checksum
'GB82-WEST-1234-5698-7654-32', // ok
'NL20INGB0001234567', // ok
'XX00 1234 5678 9012 3456 7890 1234 5678 90', // only smells ok
'YY00123456789012345678901234567890', // only smells ok
'NL20-ING-B0-00-12-34-567', // stinks, but still a valid checksum
'XX22YYY1234567890123', // wrong checksum again
'droid#i.ban' // This Is Not The IBAN You Are Looking For
];
arr.forEach(function (str) {
console.log('['+ str +'] Smells Like IBAN: '+ smellsLikeIban(str));
console.log('['+ str +'] Valid IBAN Checksum: '+ validateIbanChecksum(str))
});
Here is a suggestion that may works for the patterns you provided:
[A-Z]{2}\d{2} ?\d{4} ?\d{4} ?\d{4} ?\d{4} ?[\d]{0,2}
Try it on regex101
Explanation
[A-Z]{2}\d{2} ? 2 capital letters followed by 2 digits (optional space)
\d{4} ? 4 digits, repeated 4 times (optional space)
[\d]{0,2} 0 to 2 digits
You can use a regex like this:
^[A-Z]{2}\d{2} (?:\d{4} ){3}\d{4}(?: \d\d?)?$
Working demo
This will match only those string formats
It's probably best to look up the specifications for a correct IBAN number. But if you want to have a regex similar to your existing one, but with spaces, you can use the following one:
^[a-zA-Z]{2}[0-9]{2}\s?[a-zA-Z0-9]{4}\s?[0-9]{4}\s?[0-9]{3}([a-zA-Z0-9]\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,3})?$
Here is a live example: https://regex101.com/r/ZyIPLD/1

Zero validation Regular Expression

I have a small test to match using regex.
Match to true if and only if user has entered "0000" or 000 or 00 or 0.
0001 or 0011, 1000, 0111, 1111 should return false.
Here is what i have tried : /^0*([0]{1,4})/ but it didn't work.
This should work just fine:
/^0{1,4}$/

Violating RegExp: Every string that is smaller or equal "001700"

i have a unique challenge.
i want to create a google analytics filter for a custom variable that only returns a value if the given string is smaller or equal than '001700'. yeah, i know that a string can't be smaller, still i need to find a way to make this work.
oh, and if you ask: no there is no way to convert that string to a number (according to my knowledge - via a google analytics filter - and that is what i have to work with in this case).
so basically, i have
000000
000001
000002
000003
...
...
999998
999999
and i need a regular expression that matches
001700
001699
001698
...
...
000001
000000
but does not match
001701
001702
...
...
999998
999999
sub question a) is it possible? (as i have learned, everything is possible with regExp if you are clever and/or masochistic enough)
sub question b) how to do it?
thx very much
You can do:
^00(1700|1[0-6][0-9]{2}|0[0-9]{3})$
See it
yes you can do
see this article
Eg:
alert('your numericle string'.replace(/\d+/g, function(match) {
return parseInt(match,10) <= 17000 ? '*' : match;
}));
JavaScript calls our function, passing
the match into our match argument.
Then, we return either the asterisk
(if the number matched is under 17000) or
the match itself (i.e. no match should
take place).
Can be done with RegEx:
/00(1([0-6][0-9]{2}|700)|0[0-9]{3})/
Explanation:
00 followed by
1 followed by 0 to 6 and any 2 numbers = 1000 - 1699
or
1700
or
0 followed by any 3 numbers = 0000 - 0999

Adding an AND clause to a regex

I have this simple regex,
[\d]{1,5}
that matches any integer between 0 and 99999.
How would I modify it so that it didn't match 0, but matches 01 and 10, etc?
I know there is a way to do an OR like so...
[\d]{1,5}|[^0]{1}
(doesn't make much sense)
There a way to do an AND?
probably better off with something like:
0*[1-9]+[\d]{0,4}
If I'm right that translates to "zero or more zeros followed by at least one of the characters included in '1-9' and then up to 4 trailing decimal characters"
Mike
I think the simplest way would be:
[1-9]\d{0,4}
throw that between a ^$ if it makes sense in your case, and if so, add a 0* to the beginning:
^0*[1-9]\d{0,4}$
My vote is to keep the regex simple and do that as a separate compare outside the regex. If the regex passes, convert it to an int and make sure the converted value is > 0.
But I know that sometimes one regex in a config file or validation property on a control is all you get.
How about an OR between single digit numbers you will accept and multiple-digit numbers:
^[1-9]$|^\d{2,5}$
I think a negative lookahead would work. Try this:
#!/bin/perl -w
while (<>)
{
chomp;
print "OK: $_\n" if m/^(?!0+$)\d{1,6}$/;
}
Example trace:
0
00
000
0000
00000
000000
0000001
000001
OK: 000001
101
OK: 101
01
OK: 01
00001
OK: 00001
1000
OK: 1000
101
OK: 101
By using look-aheads you can achieve the effect of AND.
^(?=regex1)(?=regex2)(?=regex3).*
Though there is a bug in Internet Explorer, that sometimes doesn't treat (?= ) as zero-width.
http://blog.stevenlevithan.com/archives/regex-lookahead-bug
In your case:
^(?=\d{1,5}$)(?=.*?[1-9]).*
It looks like you are searching for 2 different conditions. Why not break it out to 2 expressions? It might be simpler and more readable.
var str = user_string;
if ('0' != str && str.matches(/^\d{1,5}$/) {
// code for match
}
or the following if a string of 0's is not valid as well
var str = user_string;
if (!str.matches(/^0+$/) && str.matches(/^\d{1,5}$/) {
// code for match
}
Just because you can do it all in one regex doesn't mean that you should.
^([1-9][0-9]{0,4}|[0-9]{,1}[1-9][0-9]{,3}|[0-9]{,2}[1-9][0-9]{,2}|[0-9]{,3}[1-9][0-9]|[0-9]{,4}[1-9])$
Not pretty, but it should work. This is more of a brute force approach. There's a better way to do it via grouping as well, but I'm drawing a blank on the actual implementation at the moment.