8

Looking to validate PO Box but wanted to know if such validation existed. I have the Address field split into Address 1 and Address 2 (Where such PO, Apt, Suite info would go)

Example:

Address 1: 123 Main Street
Address 2: Suite 100
City: Any Town      
State: Any State
Zip: Any Zip

PO Box (Can sub BIN for BOX as well) Examples:

  • PO Box 123
  • P.O. Box 123
  • PO 123
  • Post Office Box 123
  • P.O 123
  • Box 123
  • 123

  • 123
  • POB 123
  • P.O.B 123
  • P.O.B. 123
  • Post 123
  • Post Box 123

(I know there are probably more I need to validate for but this is what I could think of, feel free to add or correct)

I know a RegEx would be best for this and I've seen the other questions on Stack #1, #2

Using the RegEx from the other question I get good results but it misses some I think it should catch

$arr = array (
    'PO Box 123',
    'P.O. Box 123',
    'PO 123',
    'Post Office Box 123',
    'P.O 123',
    'Box 123',
    '#123',         // no match
    '123',          // no match
    'POB 123',
    'P.O.B 123',    // no match
    'P.O.B. 123',   // no match
    'Post 123',     // no match
    'Post Box 123'  // no match
);

foreach($arr as $po) {
    if(preg_match("/^\s*((P(OST)?.?\s*O(FF(ICE)?)?.?\s+(B(IN|OX))?)|B(IN|OX))/i", $po)) {
        echo "A match was found: $po\n";
    } else {
        echo "A match was not found: |$po| \n";
    }
}

Why is it not catching the last two values in the array?

Community
  • 1
  • 1
Phill Pafford
  • 83,471
  • 91
  • 263
  • 383
  • +1 for doing good research before asking question. – srijan Oct 01 '12 at 14:40
  • For a JS question but still an excellent answer: https://stackoverflow.com/questions/5680050/po-box-regular-expression-validation – tvanc Sep 22 '17 at 21:25

3 Answers3

10

As of now with your regex, the 'O' in 'OFFICE' is required. Try ^\s*((P(OST)?.?\s*(O(FF(ICE)?))?.?\s+(B(IN|OX))?)|B(IN|OX)) instead (grouping the 'O' in a conditional match).

EDIT: That should be /^\s*((P(OST)?.?\s*(O(FF(ICE)?)?)?.?\s+(B(IN|OX))?)|B(IN|OX))/i instead. BTW, http://rubular.com/ is a pretty good regular expression testing engine. Always nice to know of new tools :)

William
  • 3,511
  • 27
  • 35
  • Hmm adding that breaks this match: P.O. Box 123 – Phill Pafford Mar 01 '11 at 19:57
  • Thanks for noting that @phill-pafford, correction made in my answer. Accidentally removed one of the question marks in your original regex while testing mine. – William Mar 01 '11 at 20:01
  • I ran some tests on addresses in our system and it failed (did not recognised as PO BOX) on '41-79 Crystal Street POBox 668', 'GPO Box 837' and 'Po.Box 184'. Can you pls help to extend it? – Tomas Dermisek Jun 12 '14 at 04:05
  • 1
    This one works even for those other samples ('GPO ..' etc): /\b((?:P(?:OST)?.?\s*(?:O(?:FF(?:ICE)?)?)?.?\s*(?:B(?:IN|OX)?)+)+|(?:B(?:IN|OX)+\s+)+)\s*\w+/i – Tomas Dermisek Jun 12 '14 at 04:29
  • This seems to work the best for sure. But it also gives some false positives. I may be implementing it wrong, but I think "1111 N. Pembroke Ave." gets matched, but it is not a PO Box. That being said, I really appreciate the work you have done here as I am a novice at RegEx and this helped a lot. – Andy Borgmann Apr 03 '20 at 18:40
2

This one works better, as it removes the unneeded groups in the match set and just returns the whole match.

Skips Post 123:

/^\s*((?:P(?:OST)?.?\s*(?:O(?:FF(?:ICE)?)?)?.?\s*(?:B(?:IN|OX)?)+)+|(?:B(?:IN|OX)+\s+)+)\s*\d+/i

Doesn't Skip Post 123:

/^\s*((?:P(?:OST)?.?\s*(?:O(?:FF(?:ICE)?)?)?.?\s*(?:B(?:IN|OX)?)?)+|(?:B(?:IN|OX)+\s+)+)\s*\d+/i

Remove the \d+ at the end to skip the number requirement.

Torgo
  • 21
  • 1
2

Let's go through it...

/         # Beginning of the regex
^         # Beginning of the string
\s*       # (Any whitespace)
((
  P       # Matches your P
  (OST)?  # Matches your ost
  .?      # Matches the space
  \s*     # (Any whitespace)
  O       # Expects an O - you don't have one. Regex failed.
EboMike
  • 76,846
  • 14
  • 164
  • 167