9

I give up. I need a (PHP) regular expression that matches only 5 digit numbers starting from 01001 up to 99998.

So, invalid is for example 1234, but not 01234. Also 01000 is invalid, 01002 is not, and so on. Any other 5 digit number except 99999 is valid.

What I have is the following regular expression, which does what I require - except that it still matches 99999.

Can anyone help out? Thanks...

^01\d\d[1-9]|[1-9]\d{3}[(?<=9999)[0-8]|[0-9]]$

Update

I am sorry, everybody, but things are more complex. I did not explain correctly. German zip code can be also 04103 for example (see a list of some further examples here)

Abhranil Das
  • 5,702
  • 6
  • 35
  • 42
Hein
  • 911
  • 1
  • 8
  • 12
  • 3
    Is there a reason it has to be a regex? – Amber Oct 28 '11 at 08:16
  • 1
    I'm wondering if, for reasons of maintainability and complexity, you're not better of checking if the string consists out of all digits and then performing a numerical comparison. – Legolas Oct 28 '11 at 08:18
  • 1
    Just make damn sure there will never, ever be anybody from outside Germany filling in the form. Because stuff like this is what will drive you completely crazy when you happen to have an address abroad, for whatever reason. – Pekka Oct 28 '11 at 08:19
  • I need a regexp since it's an automated check that uses regexp to check input fields for all input fields I have... and yes, this is for german addresses only ;-) – Hein Oct 28 '11 at 08:19
  • Tag `german` removed as part of the [**2012 cleanup**](http://meta.stackexchange.com/questions/128315/the-great-stack-overflow-tag-question-cleanup-of-2012). – Abhranil Das Apr 30 '12 at 12:07

6 Answers6

21

You were close:

^0[1-9]\d\d(?<!0100)0|0[1-9]\d\d[1-9]|[1-9]\d{3}[0-8]|[1-9]\d{3}(?<!9999)9$

But if you can just do a simpler regex and then use a separate numerical comparison, that'd probably be easier to read.

Alternatively, a simpler version:

^(?!01000|99999)(0[1-9]\d{3}|[1-9]\d{4})$

(The simpler version is just "take the numbers 01000-99999 and remove the two ends via a lookahead.)

Amber
  • 507,862
  • 82
  • 626
  • 550
  • Very good with regards to 99999 - but unfortunately it does not match 20259, my former zip code... :-( – Hein Oct 28 '11 at 08:25
  • 1
    @Hein - Seems to match just fine? http://ideone.com/2N0OP (Note that there was a typo'd `]` just before the `$` before; I edited it out.) – Amber Oct 28 '11 at 08:27
  • Work's perfectly - except that I just found I'm an idiot and did not explain german zips correctly - it needs to match 04109, too... ;´-( – Hein Oct 28 '11 at 08:31
  • `^01\d{2}[1-9]|0[2-9]\d{3}|[1-9]\d{3}[0-8]|[1-9]\d{3}(?<!9999)9$` – Legolas Oct 28 '11 at 08:35
  • @Legolas Your version wouldn't match `01100`. The version I edited in does, though. – Amber Oct 28 '11 at 08:36
  • This looks pretty cool...! I'll try to check it against all german zips I'm able to generate and will let you know here.... Thanks! – Hein Oct 28 '11 at 08:39
  • The simpler version in action: http://regexpal.com/?flags=m&regex=%5E(%3F!01000%7C99999)(0%5B1-9%5D%5Cd%7B3%7D%7C%5B1-9%5D%5Cd%7B4%7D)%24&input=01000%0A01001%0A12345%0A99998%0A99999 – Amber Oct 28 '11 at 08:41
  • Cool - this is it! Thanks to all and especially to Amber! – Hein Oct 28 '11 at 08:54
  • Sure.. And next developer if will take a look at this code will just say: **oh crap** – hsz Oct 28 '11 at 08:55
  • Is there a way without lookahead/lookbehind? Because on macOS they are not supported: https://stackoverflow.com/questions/51568821/works-in-chrome-but-breaks-in-safari-invalid-regular-expression-invalid-group/51568859#51568859 – dewey Apr 04 '22 at 06:44
6

The fastest way is just to check if string is made of 5 digits and then check if it is in specified range:

if ( preg_match('/^\d{5}$/', $input) && (int) $input > 1000 && (int) $input < 99999 ) {}
hsz
  • 148,279
  • 62
  • 259
  • 315
1
\b(?!01000)(?!99999)(0[1-9]\d{3}|[1-9]\d{4})\b

Edit: corrected, thanks to Hein.

Alexey
  • 909
  • 6
  • 11
0

I found a solution to many countries.

<?php
$country_code="US";
$zip_postal="11111";

$ZIPREG=array(
    "US"=>"^\d{5}([\-]?\d{4})?$",
    "UK"=>"^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$",
    "DE"=>"\b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b",
    "CA"=>"^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])\ {0,1}(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$",
    "FR"=>"^(F-)?((2[A|B])|[0-9]{2})[0-9]{3}$",
    "IT"=>"^(V-|I-)?[0-9]{5}$",
    "AU"=>"^(0[289][0-9]{2})|([1345689][0-9]{3})|(2[0-8][0-9]{2})|(290[0-9])|(291[0-4])|(7[0-4][0-9]{2})|(7[8-9][0-9]{2})$",
    "NL"=>"^[1-9][0-9]{3}\s?([a-zA-Z]{2})?$",
    "ES"=>"^([1-9]{2}|[0-9][1-9]|[1-9][0-9])[0-9]{3}$",
    "DK"=>"^([D-d][K-k])?( |-)?[1-9]{1}[0-9]{3}$",
    "SE"=>"^(s-|S-){0,1}[0-9]{3}\s?[0-9]{2}$",
    "BE"=>"^[1-9]{1}[0-9]{3}$"
);

if ($ZIPREG[$country_code]) {

    if (!preg_match("/".$ZIPREG[$country_code]."/i",$zip_postal)){
        //Validation failed, provided zip/postal code is not valid.
    } else {
        //Validation passed, provided zip/postal code is valid.
    }

} else {

    //Validation not available

}
?>
Ahmet Uğur
  • 462
  • 6
  • 12
  • 2
    Yes and you should give a SOURCE when you post the code of someone else. In this case the original source was and still is:http://www.pixelenvision.com/1708/zip-postal-code-validation-regex-php-code-for-12-countries/ – John Nov 14 '19 at 22:03
0

Here is the ultimate strict solution for german zip codes. Unlinke other solutions, this one will accept only 5 digits (66111 = OK, 6611166111 = wrong, asd66111 = wrong).

Regex: \b((?:0[1-46-9]\d{3})|(?:[1-357-9]\d{4})|(?:[4][0-24-9]\d{3})|(?:[6][013-9]\d{3}))\b

Amel
  • 653
  • 9
  • 15
0

If you can avoid using pure regex this would validate the zip code:

function validate( $num ) {
    if( !preg_match( '/^\d{5}$/', $num ) ) {
        return false;
    }

    return ( $num > 1000 && $num < 99999 ); 
}
JJJ
  • 32,902
  • 20
  • 89
  • 102