Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regular Expression patterns for Tracking numbers

Tags:

regex

fedex

ups

Just thought I would post an update on this as I am working on this to match via jquery and automatically select the appropriate shipping carrier. I compiled a list of the matching regex for my project and I have tested a lot of tracking numbers across UPS FedEX and USPS.

If you come across something which doesn't match, please let me know here via comments and I will try to come up for that as well.

UPS:

/\b(1Z ?[0-9A-Z]{3} ?[0-9A-Z]{3} ?[0-9A-Z]{2} ?[0-9A-Z]{4} ?[0-9A-Z]{3} ?[0-9A-Z]|[\dT]\d\d\d ?\d\d\d\d ?\d\d\d)\b/

FedEX: (3 Different Ones)

/(\b96\d{20}\b)|(\b\d{15}\b)|(\b\d{12}\b)/
/\b((98\d\d\d\d\d?\d\d\d\d|98\d\d) ?\d\d\d\d ?\d\d\d\d( ?\d\d\d)?)\b/
/^[0-9]{15}$/

USPS: (4 Different Ones)

/(\b\d{30}\b)|(\b91\d+\b)|(\b\d{20}\b)/
/^E\D{1}\d{9}\D{2}$|^9\d{15,21}$/
/^91[0-9]+$/
/^[A-Za-z]{2}[0-9]+US$/

Please note that I did not come up with these myself. I simply searched around and compiled the list from different sources, including some which may have been mentioned here.

Thanks

Edit: Fixed missing end delimiter.


I need to verify JUST United States Postal Service (USPS) tracking numbers. WikiAnswers says that my number formats are as follows:

USPS only offers tracking with Express mail, with usually begins with an "E", another letter, followed by 9 digits, and two more letters. USPS does have "Label numbers" for other services that are between 16 and 22 digits long.

http://wiki.answers.com/Q/How_many_numbers_in_a_USPS_tracking_number

I'm adding in that the Label numbers start with a "9" as all the ones I have from personal shipments for the past 2 years start with a 9.

So, assuming that WikiAnswers is correct, here is my regex that matches both:

/^E\D{1}\d{9}\D{2}$|^9\d{15,21}$/

It's pretty simple. Here is the break down:

^E       - Begins w/ E  (For express number)
\D{1}    - followed by another letter
\d{9}    - followed by 9 numbers
\D{2}    - followed by 2 more letters
$        - End of string

|        - OR

^9       - Basic Track & Ship Number
\d{15,21}   - followed by 15 to 21 numbers
$        - End of string

Using www.gummydev.com's regex tester this patter matches both of my test strings:

EXPRESS MAIL : EK225651436US

LABEL NUMBER: 9410803699300003725216

**Note: If you're using ColdFusion (I am), remove the first and last "/" from the pattern


I pressed Royal Mail for a regex for the Recorded Delivery & Special Delivery tracking references but didn't get very far. Even a full set of rules so I could roll my own was beyond them.

Basically, even after they had taken about a week and came back with various combinations of letters denoting service type, I was able to provide examples from our experience that showed there were additional combinations that were obviously valid but that they had not documented.

The references follow the apparently standard international format that I think Jefe's /^[A-Za-z]{2}[0-9]+GB$/ regex would describe:

XX123456789GB

Even though this seems to be a standard format, i.e. most international mail has the same format where the last two letters denote the country of origin, I've not been able to find out any more about this 'standard' or where it originates from (any clarification welcome!).

Particular to Royal Mail seems to be the use of the first two letters to denote service level. I have managed to compile a list of prefixes that denote Special Delivery, but am not convinced that it is 100% complete:

AD AE AF AJ AK AR AZ BP CX DS EP HC HP KC KG
KH KI KJ KQ KU KV KW KY KZ PW SA SC SG SH SI
SJ SL SP SQ SU SW SY SZ TX WA WH XQ WZ

Without one of these prefixes the service is Recorded Delivery which gives delivery confirmation but no tracking.

It seems generally that inclusion of an S, X or Z denotes a higher service level and I don't think I've ever seen a normal Recorded Delivery item with any of those letters in the prefix.

However, as you can see there are many prefixes that would need to be tested if service level were to be checked using regex, and given the fact that Royal Mail seem incapable of providing a comprehensive rule set then trying to test for service level may be futile.


Here are some sample numbers from the main US carriers:

USPS:
70160910000108310009   (certified)
23153630000057728970   (signature confirmation)
RE360192014US          (registered mail)      
EL595811950US          (priority express)
9374889692090270407075 (regular)

FEDEX:
810132562702  (all seem to follow same pattern regardless) 
795223646324
785037759224

UPS:
K2479825491         (UPS ground)
J4603636537         (UPS next day express)
1Z87585E4391018698  (regular)

Patterns I am using (php code). Yep I gave up and started testing against all the patterns at my disposal. Had to write the second UPS one.

public function getCarrier($trackingNumber){



    $matchUPS1      = '/\b(1Z ?[0-9A-Z]{3} ?[0-9A-Z]{3} ?[0-9A-Z]{2} ?[0-9A-Z]{4} ?[0-9A-Z]{3} ?[0-9A-Z]|[\dT]\d\d\d ?\d\d\d\d ?\d\d\d)\b/';
    $matchUPS2      = '/^[kKJj]{1}[0-9]{10}$/';

    $matchUSPS0     = '/(\b\d{30}\b)|(\b91\d+\b)|(\b\d{20}\b)/';
    $matchUSPS1     = '/(\b\d{30}\b)|(\b91\d+\b)|(\b\d{20}\b)|(\b\d{26}\b)| ^E\D{1}\d{9}\D{2}$|^9\d{15,21}$| ^91[0-9]+$| ^[A-Za-z]{2}[0-9]+US$/i';
    $matchUSPS2     = '/^E\D{1}\d{9}\D{2}$|^9\d{15,21}$/';
    $matchUSPS3     = '/^91[0-9]+$/';
    $matchUSPS4     = '/^[A-Za-z]{2}[0-9]+US$/';
    $matchUSPS5     = '/(\b\d{30}\b)|(\b91\d+\b)|(\b\d{20}\b)|(\b\d{26}\b)| ^E\D{1}\d{9}\D{2}$|^9\d{15,21}$| ^91[0-9]+$| ^[A-Za-z]{2}[0-9]+US$/i';

    $matchFedex1    = '/(\b96\d{20}\b)|(\b\d{15}\b)|(\b\d{12}\b)/';
    $matchFedex2    = '/\b((98\d\d\d\d\d?\d\d\d\d|98\d\d) ?\d\d\d\d ?\d\d\d\d( ?\d\d\d)?)\b/';
    $matchFedex3    = '/^[0-9]{15}$/';


    if(preg_match($matchUPS1, $trackingNumber) || 
        preg_match($matchUPS2, $trackingNumber))
     {
        echo('UPS');

        $carrier = 'UPS';
        return $carrier;
    } else if(preg_match($matchUSPS0, $trackingNumber) || 
              preg_match($matchUSPS1, $trackingNumber) ||
              preg_match($matchUSPS2, $trackingNumber) ||
              preg_match($matchUSPS3, $trackingNumber) ||
              preg_match($matchUSPS4, $trackingNumber) ||
              preg_match($matchUSPS5, $trackingNumber)) {

        $carrier = 'USPS';
        return $carrier;
    } else if (preg_match($matchFedex1, $trackingNumber) || 
               preg_match($matchFedex2, $trackingNumber) || 
               preg_match($matchFedex3, $trackingNumber)) {

        $carrier = 'FedEx';
        return $carrier;
    } else if (0){
        $carrier = 'DHL';
        return $carrier;
    } 



    return;

}

I needed something more robust for my use case. I kept running across examples that were incomplete, incorrect, or overly verbose without any improvement in correctness. Hopefully this helps someone else! It covers all of the different formats in the other answers, plus a few more, and doesn't overlap between FedEx and USPS unlike some of the other answers.

Tracking Number Regular Expressions:

USPS/S10:

https://postalpro.usps.com/mnt/glusterfs/2020-02/Pub%20199%20Intelligent%20Mail%20Package%20Barcode%20(IMpb)%20Implementation%20Guide%202020_02_11%20TT%20v6.pdf

\b([A-Z]{2}\d{9}[A-Z]{2}|(420\d{9}(9[2345])?)?\d{20}|(420\d{5})?(9[12345])?(\d{24}|\d{20})|82\d{8})\b

UPS:

\b1Z[A-Z0-9]{16}\b

FedEx:

\b([0-9]{12}|100\d{31}|\d{15}|\d{18}|96\d{20}|96\d{32})\b

Caveats/notes:

  • FedEx SmartPost is [intentionally] categorized as USPS; it can be tracked with either
  • USPS includes S10 format tracking numbers used for international post
  • Tracking numbers have module check bits; these regex's don't check them
  • This was found by reading spec sheets, reading other answers, looking at open source code, etc. It matched ~6,000 tracking numbers I ran it against with 100% accuracy, but I can't be sure it will be correct in all cases.
  • These assume you've removed all whitespace before applying the regex

Example Tracking Numbers

Mostly pulled from:

  • https://tools.usps.com/go/TrackConfirmAction
  • https://github.com/jkeen/tracking_number_data
| Tracking Number                    | Kind                                | Tracking Carrier |
|------------------------------------|-------------------------------------|------------------|
| 03071790000523483741               | USPS 20                             | USPS             |
| 71123456789123456787               | USPS 20                             | USPS             |
| 4201002334249200190132607600833457 | USPS 34v2                           | USPS             |
| 4201028200009261290113185417468510 | USPS 34v2                           | USPS             |
| 420221539101026837331000039521     | USPS 91                             | USPS             |
| 71969010756003077385               | USPS 91                             | USPS             |
| 9505511069605048600624             | USPS 91                             | USPS             |
| 9101123456789000000013             | USPS 91                             | USPS             |
| 92748931507708513018050063         | USPS 91                             | USPS             |
| 9400111201080805483016             | USPS 91                             | USPS             |
| 9361289878700317633795             | USPS 91                             | USPS             |
| 9405803699300124287899             | USPS 91                             | USPS             |
| EK115095696SA                      | S10                                 | USPS             |
| 1Z5R89390357567127                 | UPS                                 | UPS              |
| 1Z879E930346834440                 | UPS                                 | UPS              |
| 1Z410E7W0392751591                 | UPS                                 | UPS              |
| 1Z8V92A70367203024                 | UPS                                 | UPS              |
| 1ZXX3150YW44070023                 | UPS                                 | UPS              |
| 986578788855                       | FedEx Express (12)                  | FedEx            |
| 477179081230                       | FedEx Express (12)                  | FedEx            |
| 799531274483                       | FedEx Express (12)                  | FedEx            |
| 790535312317                       | FedEx Express (12)                  | FedEx            |
| 974367662710                       | FedEx Express (12)                  | FedEx            |
| 1001921334250001000300779017972697 | FedEx Express (34)                  | FedEx            |
| 1001921380360001000300639585804382 | FedEx Express (34)                  | FedEx            |
| 1001901781990001000300617767839437 | FedEx Express (34)                  | FedEx            |
| 1002297871540001000300790695517286 | FedEx Express (34)                  | FedEx            |
| 61299998820821171811               | FedEx SmartPost                     | USPS             |
| 9261292700768711948021             | FedEx SmartPost                     | USPS             |
| 041441760228964                    | FedEx Ground                        | FedEx            |
| 568283610012000                    | FedEx Ground                        | FedEx            |
| 568283610012734                    | FedEx Ground                        | FedEx            |
| 000123450000000027                 | FedEx Ground (SSCC-18)              | FedEx            |
| 9611020987654312345672             | FedEx Ground 96 (22)                | FedEx            |
| 9622001900000000000000776632517510 | FedEx Ground GSN                    | FedEx            |
| 9622001560000000000000794808390594 | FedEx Ground GSN                    | FedEx            |
| 9622001560001234567100794808390594 | FedEx Ground GSN                    | FedEx            |
| 9632001560123456789900794808390594 | FedEx Ground GSN                    | FedEx            |
| 9400100000000000000000             | USPS Tracking                       | USPS             |
| 9205500000000000000000             | Priority Mail                       | USPS             |
| 9407300000000000000000             | Certified Mail                      | USPS             |
| 9303300000000000000000             | Collect On Delivery Hold For Pickup | USPS             |
| 8200000000                         | Global Express Guaranteed           | USPS             |
| EC000000000US                      | Priority Mail Express International | USPS             |
| 9270100000000000000000             | Priority Mail Express               | USPS             |
| EA000000000US                      | Priority Mail Express               | USPS             |
| CP000000000US                      | Priority Mail International         | USPS             |
| 9208800000000000000000             | Registered Mail                     | USPS             |
| 9202100000000000000000             | Signature Confirmation              | USPS             |

Been researching this for a while, and made these based mostly on the answers here.
These should cover everything, without being too lenient.
UPS:
/^(1Z\s?[0-9A-Z]{3}\s?[0-9A-Z]{3}\s?[0-9A-Z]{2}\s?[0-9A-Z]{4}\s?[0-9A-Z]{3}\s?[0-9A-Z]$|[\dT]\d{3}\s?\d{4}s?\d{3})$/i

USPS:
/^(EA|EC|CP|RA)\d{9}(\D{2})?$|^(7\d|03|23|91)\d{2}\s?\d{4}\s?\d{4}\s?\d{4}\s?\d{4}(\s\d{2})?$|^82\s?\d{3}\s?\d{3}\s?\d{2}$/i

FEDEX:
/^(((96|98)\d{5}\s?\d{4}$|^(96|98)\d{2})\s?\d{4}\s?\d{4}(\s?\d{3})?)$/i