Regular Expression patterns for Tracking numbers

53,577

Solution 1

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.

Solution 2

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

Solution 3

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:

| 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             |

Solution 4

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.

Solution 5

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;

}
Share:
53,577
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    Does anybody know good place or patterns for checking which company tracking number is the given tracking number for a package. Idea is After scanning a barcode for a package check tracking number with patterns and show which company it was shipped by.

  • Safran Ali
    Safran Ali almost 13 years
    you should put this as a comment in the question because this area is used for answering. And if you put over there it'll be much notifiable by other people so they can re-write the regex or suggest any alternatives.
  • SS44
    SS44 over 11 years
    UPS also has Mail Innovations Tracking Numbers (ups.com/content/us/en/tracking/help/tracking/tnh.html) so I had to ammend you ups regex to /\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|\d{22})\b/i to include these
  • Jared Sealey
    Jared Sealey over 11 years
    The USPS Regex does not match as many tracking numbers as Adil's solution: stackoverflow.com/a/5024011/1166066
  • Semicolon
    Semicolon almost 11 years
    (Updating this years-old answer, in case someone happens across it now): Today, USPS domestic numbers begin with 92, 93, 94 or 95. That number is the 'channel application identifier', which indicates what USPS channel issued the number (purchased at a post office, purchased online, etc). 91 has been retired.
  • ColinM
    ColinM almost 11 years
    Note that the "9612019" is some sort of prefix (FedEx Ground?) and the tracking number could be abbreviated as "059803563050071" and would be a valid FedEx tracking number lookup.
  • jkelley
    jkelley over 10 years
    You missed one \s at the end of the UPS regex. I also pulled out the $: /^(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
  • jkelley
    jkelley over 10 years
    Also, small change on USPS. One of the \s should be optional, so I added an extra ?: /^(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
  • Ray
    Ray over 8 years
    USPS changed some tracking numbers to 26 char. Use: /(\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
  • DBagBaggerWithSwagger
    DBagBaggerWithSwagger about 8 years
    There's a Ruby library called tracking_number. It does a lot to identify tracking numbers. I suggest you check it out.
  • stackOverFlew
    stackOverFlew over 7 years
    @SS44 your regex reads a USPS number, so it's too loose. (9374889692090270407075 is a USPS number and your regex matches it)
  • Purgatory
    Purgatory over 7 years
    There are some codes that Royal mail have deemed invalid so I have adjusted the above to exclude those: /(?!(EA|EB|EC|ED|EE|CP))[A-Za-z]{2}[0-9]{9}+GB/ if your string only contains the tracking number then use the start and end symbols like so /^(?!(EA|EB|EC|ED|EE|CP))[A-Za-z]{2}[0-9]{9}+GB$/
  • Lunatik
    Lunatik over 7 years
    Great info. Where did you get that from?
  • Purgatory
    Purgatory over 7 years
    If you are referring to the invalid prefixes then it is on the documentation on their website. royalmail.com/royal-mail-you/intellectual-property-rights/…
  • dataviews
    dataviews over 5 years
    for these tracking emails, did you have to extract information about what was shipped? For example, an order number, product information, etc?
  • dataviews
    dataviews over 5 years
    How are you handling duplicate matches? For instance, I have run into the issue for 22 digit numbers for USPS being caught by the UPS regex (if you look below, the number can be 22-34 digits for Mail Innovations).
  • user3431501
    user3431501 about 4 years
    tracking-number-validation is a JavaScript library that worked well in my React Native project.
  • pbarranis
    pbarranis over 2 years
    I'm a bit of a regex n00b. Is there a reason you used \d\d\d instead of \d{3} (and so on)?