hh-shipments 0.3.4 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -18,7 +18,7 @@
18
18
  "test": "node test/run-tests.js && node test/run-carriers-tests.js"
19
19
  },
20
20
  "type": "commonjs",
21
- "version": "0.3.4",
21
+ "version": "0.3.5",
22
22
  "bin": {
23
23
  "hh-shipments": "server.js"
24
24
  },
package/public/extract.js CHANGED
@@ -111,6 +111,9 @@
111
111
  }
112
112
 
113
113
  function extractOcrTolerant(text, found, seen) {
114
+ // Strict UPS structure: 1Z + 6-char shipper number + 2-digit service + 8-digit serial.
115
+ // Used to validate "1Z"-as-"12" OCR repairs so we don't invent false positives.
116
+ var UPS_STRICT = /^1Z[0-9A-Z]{6}[0-9]{2}[0-9]{8}$/;
114
117
  function push(num, carrier, confidence, extra) {
115
118
  num = normalize(num);
116
119
  if (!num || seen[num]) return;
@@ -119,11 +122,27 @@
119
122
  if (extra) for (var k in extra) c[k] = extra[k];
120
123
  found.push(c);
121
124
  }
122
- // a) UPS number split by spaces/dashes: "1Z 9999 99 ..."
123
- var m, spacedUps = /\b1Z[\s-]?(?:[0-9A-Z][\s-]?){16}\b/gi;
125
+ function repairUpsZ(ups) {
126
+ // Tesseract often reads the "1Z" anchor as "12" (or "IZ"). Repair it
127
+ // only when the rest has strict UPS structure AND the shipper segment
128
+ // contains a letter — real UPS shipper numbers do, random digit runs
129
+ // don't. Never invent numbers from thin air.
130
+ var cand = null;
131
+ if (/^12[0-9A-Z]{16}$/.test(ups)) cand = '1Z' + ups.slice(2);
132
+ else if (/^IZ[0-9A-Z]{16}$/i.test(ups)) cand = '1Z' + ups.slice(2);
133
+ if (!cand || !UPS_STRICT.test(cand)) return null;
134
+ if (!/[A-Z]/.test(cand.slice(2, 8))) return null;
135
+ return cand;
136
+ }
137
+ // a) UPS number split by spaces/dashes: "1Z 9999 99 ..." (or "12 ..."/"IZ ..." misreads)
138
+ var m, spacedUps = /\b(?:1Z|12|IZ)[\s-]?(?:[0-9A-Z][\s-]?){16}\b/gi;
124
139
  while ((m = spacedUps.exec(text)) !== null) {
125
140
  var ups = normalize(m[0]);
126
141
  if (/^1Z[0-9A-Z]{16}$/.test(ups)) push(ups, 'ups', 'medium');
142
+ else {
143
+ var fixed = repairUpsZ(ups);
144
+ if (fixed) push(fixed, 'ups', 'medium');
145
+ }
127
146
  }
128
147
  // b) long digit-like runs with OCR confusions -> fix -> re-match digit formats
129
148
  var runRe = /[0-9OILSBoilszb]{10,24}/g, run;
@@ -145,6 +164,13 @@
145
164
  });
146
165
  tokens.sort(function (a, b) { return b.length - a.length; });
147
166
  tokens.slice(0, 3).forEach(function (t) {
167
+ // UPS "1Z" misread as "12"/"IZ" in a joined (space-free) token
168
+ var fixed = repairUpsZ(t);
169
+ if (fixed) { push(fixed, 'ups', 'medium'); return; }
170
+ // OCR-fixed variant may match a carrier format (e.g. I->1 at the start)
171
+ var digitFixed = ocrDigitFix(t);
172
+ var gc = guessCarrier(digitFixed);
173
+ if (gc !== 'unknown') { push(digitFixed, gc, 'low', { possible: true }); return; }
148
174
  push(t, guessCarrier(t), 'low', { possible: true });
149
175
  });
150
176
  }
package/src/extract.js CHANGED
@@ -111,6 +111,9 @@
111
111
  }
112
112
 
113
113
  function extractOcrTolerant(text, found, seen) {
114
+ // Strict UPS structure: 1Z + 6-char shipper number + 2-digit service + 8-digit serial.
115
+ // Used to validate "1Z"-as-"12" OCR repairs so we don't invent false positives.
116
+ var UPS_STRICT = /^1Z[0-9A-Z]{6}[0-9]{2}[0-9]{8}$/;
114
117
  function push(num, carrier, confidence, extra) {
115
118
  num = normalize(num);
116
119
  if (!num || seen[num]) return;
@@ -119,11 +122,27 @@
119
122
  if (extra) for (var k in extra) c[k] = extra[k];
120
123
  found.push(c);
121
124
  }
122
- // a) UPS number split by spaces/dashes: "1Z 9999 99 ..."
123
- var m, spacedUps = /\b1Z[\s-]?(?:[0-9A-Z][\s-]?){16}\b/gi;
125
+ function repairUpsZ(ups) {
126
+ // Tesseract often reads the "1Z" anchor as "12" (or "IZ"). Repair it
127
+ // only when the rest has strict UPS structure AND the shipper segment
128
+ // contains a letter — real UPS shipper numbers do, random digit runs
129
+ // don't. Never invent numbers from thin air.
130
+ var cand = null;
131
+ if (/^12[0-9A-Z]{16}$/.test(ups)) cand = '1Z' + ups.slice(2);
132
+ else if (/^IZ[0-9A-Z]{16}$/i.test(ups)) cand = '1Z' + ups.slice(2);
133
+ if (!cand || !UPS_STRICT.test(cand)) return null;
134
+ if (!/[A-Z]/.test(cand.slice(2, 8))) return null;
135
+ return cand;
136
+ }
137
+ // a) UPS number split by spaces/dashes: "1Z 9999 99 ..." (or "12 ..."/"IZ ..." misreads)
138
+ var m, spacedUps = /\b(?:1Z|12|IZ)[\s-]?(?:[0-9A-Z][\s-]?){16}\b/gi;
124
139
  while ((m = spacedUps.exec(text)) !== null) {
125
140
  var ups = normalize(m[0]);
126
141
  if (/^1Z[0-9A-Z]{16}$/.test(ups)) push(ups, 'ups', 'medium');
142
+ else {
143
+ var fixed = repairUpsZ(ups);
144
+ if (fixed) push(fixed, 'ups', 'medium');
145
+ }
127
146
  }
128
147
  // b) long digit-like runs with OCR confusions -> fix -> re-match digit formats
129
148
  var runRe = /[0-9OILSBoilszb]{10,24}/g, run;
@@ -145,6 +164,13 @@
145
164
  });
146
165
  tokens.sort(function (a, b) { return b.length - a.length; });
147
166
  tokens.slice(0, 3).forEach(function (t) {
167
+ // UPS "1Z" misread as "12"/"IZ" in a joined (space-free) token
168
+ var fixed = repairUpsZ(t);
169
+ if (fixed) { push(fixed, 'ups', 'medium'); return; }
170
+ // OCR-fixed variant may match a carrier format (e.g. I->1 at the start)
171
+ var digitFixed = ocrDigitFix(t);
172
+ var gc = guessCarrier(digitFixed);
173
+ if (gc !== 'unknown') { push(digitFixed, gc, 'low', { possible: true }); return; }
148
174
  push(t, guessCarrier(t), 'low', { possible: true });
149
175
  });
150
176
  }