Postcode & Regex

Hello all,

I’m not very good at regex, so I could do with someone’s help to work out how I fix this.

My client’s website only delivers to 5 postcodes in the UK - AL1, AL3, AL4, AL5 and NG9

I currently have the following regex set up for their delivery area;

[nN][gG]9|([aA][lL]1)|([aA][lL]3)|[aA][lL]4|[aA][lL]5

This works OK, but I’ve been made aware that any postcode with an extra number that starts with one of the above is also being accepted, e.g. AL10 or AL11 also works.

I’ve tried using regexr.com to try and end the string or similar before the second number, but can’t work it out.

Can anyone help please?

Thanks.

You don’t need the multiple conditions for each number because you can include them in square brackets just like you did uppercase or lowercase letters. So simplify this to:

([nN][gG]9|[aA][lL][1|3-5])

And then add \d? to the end. \d is any digit, and ? means 0 or 1 - so it’s optional.

And to make sure that A1T or A553 or whatever wouldn’t pass, you add \b - boundary assertion - to signify that’s the end of that part of the postal code. So it ends with either one or two digits.

([nN][gG]9|[aA][lL][1|3-5])\d?\b

And if the postal code must start with this, so add ^ (start of the input) at the beginning.

^([nN][gG]9|[aA][lL][1|3-5])\d?\b

1 Like

You’re a hero, thank you so much; great explanation. I will give it a try.

1 Like

Hi @rodrigojmr

I’ve got the same situation here, so here is my original and my attempt; would you be able to feedback on this for me, please?

[sS][gG]4|[sS][gG]1|[aA][lL]6|[aA][lL]7|[aA][lL]10|[aA][lL]2|[wW][dD]23|[wW][dD]25|[wW][dD]7|[hH][pP]3|[wW][dD]4|[hH][pP]1|[aA][lL]3|[lL][uU]1|[hH][pP]4
^([sS][gG]1|([aA][lL][6-7|10|2-3]|[wW][dD][23|25|7|4]|[hH][pP][1|3-4]|[lL][uU]1)\d?\b

From the code you sent me, you had a syntax error. The parenthesis at ([aA][lL] was extraneous, so the regex stopped working.

It overall looks good but there’s something to fix. Remember this: that any postcode with an extra number that starts with one of the above ?

I am assuming that will not apply for WD23 (so you don’t want to match WD236) but since the \d? applies to any of the previously matched group, that happens.

So, this will work if any of the single digit groups you’ve done (AL6, WD4, HP3, etc.) might have an extra number after them and you want to accept them, but the double digit groups (AL10, WD25, etc) do not.

^([sS][gG]1|[aA][lL][6-7|10|2-3]|[wW][dD][23|25|7|4]|[hH][pP][1|3-4]|[lL][uU]1)(?<!\d{2})\d?\b

What I added was (?<!\d{2}) before \d?, making it this expression: (?<!\d{2})\d?

This means it’s gonna do a look behind (?<) and it’s a negative affirmation (!) of two digits (\d{2}), and it means it’ll apply the expression after the parenthesis that contains the look behind - \d? is after (?<!\d{2}) - to strings that DON’T already have two digits.

AL67 passes (7 was allowed by the \d after the negative lookbehind, as 6 is only one digit. But WD236 does not, as WD23 already has two digits.

Ok, now that’s with the assumption any single digit group you wrote out would be able to accept any other digit after it. But if it doesn’t, like AL4 could accept it but WD7 or HP3 cannot, I think you’ll need to a more complicated lookbehind, or put the \d? into the different OR (|) groups rather than apply to all of them. If that’s the case say so, then I can help, but for now that’s my solution.

Hello

Wow that’s a lot to take in - thank you for trying to help me.

I’ve tried to follow your explanation here.

So, in essence, I need the following postcodes and only these to work:

  • SG1
  • SG4
  • AL2
  • AL3
  • AL6
  • AL7
  • AL10
  • WD4
  • WD7
  • WD23
  • WD25
  • HP1
  • HP3
  • HP4
  • LU1

I’m well out of my depth on this one, and struggling to get my head around it if you can help me out, please?

No problem.

But is this still the case:

AL1, AL3, AL4, AL5 and NG9

This works OK, but I’ve been made aware that any postcode with an extra number that starts with one of the above is also being accepted, e.g. AL10 or AL11 also works.

? Or only for those AL and NG?

Ah, sorry, I think I’ve confused you.

You solved the original issue - those 5 postcodes originally are for their free delivery area.

The newer postcodes are for a separate delivery charge, so they’re totally different shipping option inside Snipcart. I have noticed a duplicate, however, so the refined new list will be:

  • SG1
  • SG4
  • AL2
  • AL6
  • AL7
  • AL10
  • WD4
  • WD7
  • WD23
  • WD25
  • HP1
  • HP3
  • HP4
  • LU1

Oh haha alright no problem then, that should be pretty simple then, you basically solved it - only missed one number and had the parenthesis syntax error.

^([sS][gG][1|4]|[aA][lL][6-7|10|2-3]|[wW][dD][23|25|7|4]|[hH][pP][1|3-4]|[lL][uU]1)\b

Also this site should help: regex101: build, test, and debug regex You care about the matches - either green visual or in the sidebar it lists all the matches.

BTW, how does the user input the postal code? Is it just those entries or do they enter any more text in the same input? I was hoping the \b didn’t break anything.

Edited my comment, removed the \d?. Again, that will work if you only need those specifically to work, and none of them take possible digits you didn’t list (SG45, AL72, etc wouldn’t work). Just to make sure, if any of them do also need that possible extra digit, list them out.

This is the site: https://www.zuckermausbakery.com/

Using your adjusted version, it still lets AL1 pass?

Right, I wrote it incorrectly.

Here:

^([sS][gG][1|4]|[aA][lL](2|3|6|7|10)|[wW][dD](4|7|23|25)|[hH][pP][1|3-4]|[lL][uU]1)\b

Changed here. I’ll add a few spaces so I hope it’s clearer. Instead of using [] which is just a single character matching the set, since you now have two digit numbers, you use ()

[aA][lL] (2|3|6|7|10)
[wW][dD] (4|7|23|25)

Parenthesis () with | means an OR statement.

That can actually be done to the other numbers, not necessary to those that don’t have a two digit possible match, but might make it clearer. Also, the range character - only works inside [], so we don’t do 3-4, we’d do (3|4).

^([sS][gG](1|4)|[aA][lL](2|3|6|7|10)|[wW][dD](4|7|23|25)|[hH][pP](1|3|4)|[lL][uU]1)\b

Also fair warning, if you copy paste this code it’ll probably make a link in markdown so to cancel the markdown link creation of [link](url) results in link, you use slash before the first parenthesis: [hey this pastes as a]\(regex expression and not a link)

1 Like

Thank you! I will give that a try.