16

Here's my code, but I can't ever trigger the alert.

$(document).ready( function (){
    $("[id*='txtAddress1S']").blur(function() {
        var pattern = new RegExp('\b[P|p]*(OST|ost)*\.*\s*[O|o|0]*(ffice|FFICE)*\.*\s*[B|b][O|o|0][X|x]\b');
        if ($("[id*='txtAddress1S']").val().match(pattern)) {
            alert('We are unable to ship to a Post Office Box.\nPlease provide a different shipping address.'); 
        }

    });
});
TylerH
  • 20,816
  • 57
  • 73
  • 92
s15199d
  • 6,678
  • 9
  • 41
  • 64

14 Answers14

43

I tried several PO Box RegExp patterns found on the internet including the ones posted on Stack Overflow, none of them passed our test requirements. Hence, I posted our RegExp below and our test sets:

var poBox = /^ *((#\d+)|((box|bin)[-. \/\\]?\d+)|(.*p[ \.]? ?(o|0)[-. \/\\]? *-?((box|bin)|b|(#|n|num|number)?\d+))|(p(ost|ostal)? *(o(ff(ice)?)?)? *((box|bin)|b)? *(#|n|num|number)*\d+)|(p *-?\/?(o)? *-?box)|post office box|((box|bin)|b) *(#|n|num|number)? *\d+|(#|n|num|number) *\d+)/i;

var matches = [ //"box" can be substituted for "bin" 
    "#123", 
    "Box 123", 
    "Box-122", 
    "Box122", 
    "HC73 P.O. Box 217", 
    "P O Box125", 
    "P. O. Box", 
    "P.O 123", 
    "P.O. Box 123", 
    "P.O. Box", 
    "P.O.B 123",
    "P.O.B. 123", 
    "P.O.B.", 
    "P0 Box", 
    "PO 123", 
    "PO Box N", 
    "PO Box", 
    "PO-Box", 
    "POB 123", 
    "POB", 
    "POBOX123",
    "Po Box", 
    "Post 123", 
    "Post Box 123", 
    "Post Office Box 123", 
    "Post Office Box", 
    "box #123", 
    "box 122", 
    "box 123", 
    "number 123", 
    "p box", 
    "p-o box", 
    "p-o-box", 
    "p.o box", 
    "p.o. box", 
    "p.o.-box", 
    "p.o.b. #123", 
    "p.o.b.", 
    "p/o box", 
    "po #123", 
    "po box 123", 
    "po box", 
    "po num123", 
    "po-box", 
    "pobox", 
    "pobox123", 
    "post office box", 
    "Post Box #123" 
];

var nonMatches = [ 
    "The Postal Road", 
    "Box Hill", 
    "123 Some Street", 
    "Controller's Office", 
    "pollo St.", 
    "123 box canyon rd", 
    "777 Post Oak Blvd", 
    "PSC 477 Box 396", 
    "RR 1 Box 1020" 
]; 
sm83
  • 15
  • 6
Dathan
  • 1,085
  • 1
  • 9
  • 11
  • 777 Post Offie Box = returns false – kadalamittai Dec 11 '15 at 16:44
  • this seems to miss `Post Box #123` – anson Apr 14 '16 at 17:29
  • 2
    I think this one makes sense except for the "#123" being a valid po box – Cole W Sep 19 '16 at 18:55
  • This one doesn't match "123 P Street", "34 PO Road", or "777 Post Office Box Road", which I think is correct. This answer FTW! – Wesley Musgrove Oct 20 '17 at 13:09
  • 2
    I removed pound sign (like the first test #123) because that could be a valid building number or something: ^ *(((box|bin)[-. \/\\]?\d+)|(.*p[ \.]? ?(o|0)[-. \/\\]? *-?((box|bin)|b|(#|num)?\d+))|(p(ost)? *(o(ff(ice)?)?)? *((box|bin)|b)? *\d+)|(p *-?\/?(o)? *-?box)|post office box|((box|bin)|b) *(number|num|#)? *\d*\d+) – Tony Smith Aug 02 '18 at 19:56
  • This also matches "Expo Boulevard". – Nik S Sep 12 '18 at 01:31
  • 3
    Realize this old but it still ranks high in Google. The above regex fails on a number of valid addresses, just FYI for anyone finding this. Examples: 123 Harpo Box Street, 123 Poblano Lane – rg88 May 24 '19 at 15:57
  • If you want to include "postal" then change `p(ost)?` to `p(ost|ostal)?` – Ryan Walker Jun 03 '20 at 22:13
20

In javascript, you have to escape your slashes:

var pattern = new RegExp('\\b[P|p]*(OST|ost)*\\.*\\s*[O|o|0]*(ffice|FFICE)*\\.*\\s*[B|b][O|o|0][X|x]\\b');

Also, you could reduce your pattern a bit by using case-insensitive matching:

var pattern = new RegExp('\\b[p]*(ost)*\\.*\\s*[o|0]*(ffice)*\\.*\\s*b[o|0]x\\b', 'i');

Note: Your regex also matches on addresses such as:

  • 123 Poor Box Road
  • 123 Harpo Box Street

I would suggest also checking for a number in the string. Perhaps this pattern from a previous answer would be of some help:

var pattern = new RegExp('[PO.]*\\s?B(ox)?.*\\d+', 'i');

(it won't match on "Post Office" spelled out, or the numeric replacements.. but it's a start.)

Community
  • 1
  • 1
drudge
  • 33,309
  • 7
  • 32
  • 42
6

With Javascript its easier to use a regex literal like so:

var pattern = /\b(?:p\.?\s*o\.?|post\s+office)\s+box\b/i;

(No backslashes required!)

ridgerunner
  • 32,251
  • 4
  • 54
  • 68
3

This is what i have used accounting for spaces and case insensitive:

http://regexr.com/3cc2q

var pattern = /\bP(ost|ostal)?([ \.]*(O|0)(ffice)?)?([ \.]*Box)\b/i;
  • fail - po box
  • fail - p.o. box
  • fail - po bo
  • fail - post office box
  • fail - P.O. Box
  • fail - PO. Box
  • fail - PO Box
  • fail - POBox
  • fail - P O Box
  • fail - P.O Box
  • fail - PO
  • fail - Postal Box
  • fail - Post Office Box
  • pass - poop box
  • pass - pony box
Jonathan Marzullo
  • 6,699
  • 2
  • 39
  • 46
2

We ran into false positive PO Boxes after using @Dathan's answer in production for a few months. This simplified version ensures the pattern is followed by a number so won't match things like "Expo Blvd". It also allows things like "#123" and "B1" commonly found in address2 fields for apartment/unit/suite numbers. You can play around with it and add your own test cases here: https://regex101.com/r/7ZUQFl/2

const re = /^\s*(.*((p|post)[-.\s]*(o|off|office)[-.\s]*(b|box|bin)[-.\s]*)|.*((p|post)[-.\s]*(o|off|office)[-.\s]*)|.*((p|post)[-.\s]*(b|box|bin)[-.\s]*)|(box|bin)[-.\s]*)(#|n|num|number)?\s*\d+/i;
const matches = [
  "post office box 1",
  "post office b 1",
  "post off box 1",
  "post off b 1",
  "post o box 1",
  "post o b 1",
  "p office box 1",
  "p office b 1",
  "p off box 1",
  "p off b 1",
  "p o box 1",
  "p-o-b-1",
  "p.o.b.1",
  "POB1",
  "pob #1",
  "pob num1",
  "pob number1",
  "foo pob1",
  "box #1",
  "po 1",
  "pb 1"
];
const nonMatches = [ 
  "Expo Blvd",
  "Rural Route Box 1",
  "Army Post 1",
  "B1",
  "#1",
  "N1",
  "Number 1",
  "Num 1"
];
rocky
  • 997
  • 1
  • 11
  • 18
2

I found a pattern that works for most realistic post office addresses. Also had to fall to this after getting false positive with @jonathan-marzullo's answer for Rural Route Post 1 which is not a postal address.

My pattern is

pattern = P([.]?(O|0)[.]?|ost|ostal).((O|0)ffice.)?Box{1}\b/i

Matches for the following cases:

PO Box
P.O. Box
PO. Box
po box
P.o box
po box
p.o. box
post office box
P.O. Box
PO. Box
PO Box
Postal Box
Post Office Box
P.O Box
post office box 1
postal office box 1
postal box 1

Doesn't match the following cases:

post office b 1
post off box 1
post off b 1
post o box 1
post o b 1
p office box 1
p office b 1
p off box 1
p off b 1
p o box 1
p-o-b-1
p.o.b.1
POB
pob #1
pob num1
pob number1
foo pob1
box #1
po 1
pb 1
Expo Blvd
Rural Route Box 1
Army Post 1
postal office 1
poop box
pony box
POBox
P O Box
PO
po bo
Pobox
Post
Suraj Rao
  • 28,850
  • 10
  • 94
  • 99
Jatto_abdul
  • 109
  • 2
  • 11
1

This one is working pretty well for us. (php preg_match)

$pattern = '!p(ost)?\.?\s*o(ffice)?\.?(box|\s|$)!i';
mohrt
  • 444
  • 5
  • 2
1

This regex works for me in all the scenarios. The main difference between

^([ A-Za-z0-9_:/#,]*)((((((P(ost(al)?)?)|(Mail(ing)?)))([ \\./#-]*)((((O|0)(ffice)?)|(B(ox|in)?))))|(B(ox|in)?))([ \\./#-]*))(B(ox|in)?)?(([ \\./#-]*)((n(um(ber)?)?)|no)?)([ \\.:/#-]*)([0-9]+)([ A-Za-z0-9_:/#,]*)$

This regular expression matches the following set of address patterns.

I also added ([ A-Za-z0-9_:/#,]*) pattern in the beginning as well as at the end to support the presence of the patterns in between any other address string. Such as 123 Main St, P.O.Box 458.

The construct is defined as follows: (((Postal|Mailing){SEP}(Office|(Box|Bin)))|(Box|Bin)){SEP}(Box|Bin)?{SEP}(number|no){SEP}([0-9]+)

It addresses the concerns mentioned above by anson, drudge, rocky, jatto abdul

This is validated using Java 8+

Pattern pattern = Pattern.compile(REG_EX, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE );

boolean result = pattern.matcher(sequence).matches();

Passed

  • P.O. Box: true
  • p.O. Box: true
  • p.o. Box: true
  • PO Box: true
  • Post Office Box: true
  • Post Box: true
  • po box: true
  • post b: true
  • po b: true
  • Post: true
  • Postal Office: true
  • Post Office Box: true
  • Postal Office Box: true
  • Mailing Office Box: true
  • Mail box: true
  • Box 123: true
  • Box-122: true
  • Box122: true
  • HC73 P.O. Box 217: true
  • P O Box125: true
  • P. O. Box: true
  • P.O 123: true
  • P.O. Box 123: true
  • P.O. Box: true
  • P.O.B 123: true
  • P.O.B. 123: true
  • P.O.B.: true
  • P0 Box: true
  • PO 123: true
  • PO Box: true
  • PO-Box: true
  • POB 123: true
  • POB: true
  • POBOX123: true
  • Po Box: true
  • Post 123: true
  • Post Box 123: true
  • Post Office Box 123: true
  • Post Office Box: true
  • box #123: true
  • box 122: true
  • box 123: true
  • P box: true
  • P-o box: true
  • P-o-box: true
  • P.o box: true
  • P.o. box: true
  • P.o.-box: true
  • P.o.b. #123: true
  • P.o.b.: true
  • P/o box: true
  • Po #123: true
  • Po box 123: true
  • Po box: true
  • Po num123: true
  • Po-box: true
  • Pobox: true
  • Pobox123: true
  • Post office box: true
  • Post Box #123: true

Failed

  • PO Box N: false
  • number 123: false
  • #123: false ( mentioned by Cole W. I removed it based on the similar logic mentioned by Tony Smith )
  • 123 Main St: false
  • 123 Poor Box St: false
  • 123 Poor Box Road: false
  • 123 Bin St: false
  • 123 Harpo Box Street: false
  • 123 Poblano Lane: false
  • The Postal Road: false
  • Box Hill: false
  • 123 Some Street: false
  • Controller's Office: false
  • pollo St.: false
  • 123 box canyon rd: false
  • 777 Post Oak Blvd: false
  • While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Yunnosch Feb 22 '22 at 18:02
  • I couldn't get 'Post 123' to pass using this, so I made a very small addition: a `?` after the first group with box/bin/etc. `/^([ A-Za-z0-9_:/#,]*)((((((p(ost(al)?)?)|(mail(ing)?)))([ \\./#-]*)((((o|0)(ffice)?)|(b(ox|in)?)))?)|(b(ox|in)?))([ \\./#-]*))(b(ox|in)?)?(([ \\./#-]*)((n(um(ber)?)?)|no)?)([ \\.:/#-]*)([0-9]+)([ A-Za-z0-9_:/#,]*)$/im` for Javascript. – Abe May 19 '22 at 23:38
0

Its worked for me,

var poRegex = /\bP(ost|ostal)?([ \.]*O(ffice)?)?([ \.]*Box)?\b/i;
0

Here's one that matches 'POB', 'PO Box'and 'Post Office Box'. Pattern:

\\b[PO.|Post\\sOffice]*\\s?B(ox)?.*\\d+\\b.

It's a modification of @drudge's solution.

baeyun
  • 230
  • 1
  • 6
0

The regex provided above is accepting PO box which is correct. Modified Regex not to accept is:

var pattern = /^ *(?!(#\d+)|((box|bin)[-. \/\\]?\d+)|(.*p[ \.]? ?(o|0)[-. \/\\]? *-?((box|bin)|b|(#|num)?\d+))|(p(ost)? *(o(ff(ice)?)?)? *((box|bin)|b)? *\d+)|(p *-?\/?(o)? *-?box)|post office box|((box|bin)|b) *(number|num|#)? *\d+|(num|number|#)|(?![a-zA-Z0-9\x20'#,]) *\d+)/i;
mcvnpvsr
  • 141
  • 1
  • 6
0

JavaScript:

^\b[P|p]*(OST|ost)*\.*\s*[O|o|0]*(ffice|FFICE)*\.*\s*[B|b][O|o|0][X|x]\b

You just need to start the regex with ^, like: ^\b[P|p]......

TylerH
  • 20,816
  • 57
  • 73
  • 92
  • Please take the time to point out what you changed in the Regex and why. For older questions with existing answers it is really useful to explain how your answer differs and if the passage of time since it was asked has made different answers available. – Jason Aller Sep 04 '19 at 17:12
0

Here is my version(in Java):

  1. It should have a number after PO BOX
  2. A valid PO BOX can be part of a longer address like "My address details PO BOX 123" is a valid PO BIN address.
  3. It can use BIN instead of BOX
import java.util.Random;
import java.util.regex.Pattern;

public class Demo {
    public static final Pattern POST_OFFICE_BOX_PATTERN = Pattern.compile("([\\w\\s*\\W]*(P(OST)?.?\\s*((O(FF(ICE)?)?)?.?\\s+B(IN|OX))+))\\s*\\d+[\\w\\s*\\W]*");

    public static void main(String[] args) {
        testInvalidAddresses();
        testValidAddresses();
    }

    public static void testValidAddresses() {
        String[] matches = new String[]{"HC73 P.O. Box 217",
                "P O Box125",
                "P.O. Box 123",
                "PO Box " + Math.abs(new Random().nextInt()),
                "PO Bin " + Math.abs(new Random().nextInt()),
                "Post Office Box 123",
                "Post Office Bin 123",
                "Post Off. Box 123",
                "Post Box 123",
                "po bin 123"};

        for (String address : matches) {
            boolean isPoBox = isValidPostOfficeBox(address.toUpperCase());
            if (!isPoBox) {
                throw new IllegalArgumentException(address);
            }
        }
    }

    public static void testInvalidAddresses() {
        var noMatches = new String[]{"#123",
                "Box 123",
                "Box-122",
                "Box122",
                "P. O. Box",
                "P.O. Box",
                "P.O.B 123",
                "P.O.B. 123",
                "P.O.B.",
                "P0 Box",
                "PO 123",
                "PO Box",
                "PO-Box",
                "POB 123",
                "POB",
                "POBOX123",
                "Po Box",
                "Post 123",
                "Post Office Box",
                "box #123",
                "box 122",
                "box 123",
                "p box",
                "p-o box",
                "p-o-box",
                "p.o box",
                "p.o. box",
                "p.o.-box",
                "p.o.b. #123",
                "p.o.b.",
                "p/o box",
                "po #123",
                "po bin",
                "po box",
                "po num123",
                "po-box",
                "pobox",
                "pobox123",
                "post office box",
                "The Postal Road",
                "Box Hill",
                "123 Some Street",
                "Controller's Office",
                "pollo St.",
                "123 box canyon rd",
                "777 Post Oak Blvd",
                "PSC 477 Box 396",
                "RR 1 Box 1020",
                "PzBzzzzzzzzz",
                "PzzBzzzzzzzzz",
                "PzzzBzzzzzzzzz",
                "PzzzzBzzzzzzzzz",
                "zzzPzBzzzzzzzzz",
                "zzzPzzBzzzzzzzzz",
                "zzzPzzzBzzzzzzzzz",
                "zzzPzzzzBzzzzzzzzz",
                "P.O 123",
                "Washington Post 42",
                "PO binary 123",
                "p b",
                "p  b",
                "Piebert",
                "Pebble",
                "pb"};

        for (String address : noMatches) {
            boolean isPoBox = isValidPostOfficeBox(address);
            if (isPoBox) {
                throw new IllegalArgumentException(address);
            }
        }
    }

    public static boolean isValidPostOfficeBox(String value) {
        if (value != null) {
            return POST_OFFICE_BOX_PATTERN.matcher(value.toUpperCase()).matches();
        }
        return false;
    }
}
valijon
  • 1,076
  • 1
  • 16
  • 30
0

If you stripped out all the dots "." and spaces then converted it lower case you would only need to check if the string starts with pob or postofficebox,

(credit BarCotter)

Abe
  • 170
  • 1
  • 9