@lhncbc/ucum-lhc 5.0.0 → 5.0.3
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/README.md +50 -12
- package/browser-dist/ucum-lhc.js +731 -1265
- package/data/ucumDefs.min.json +1 -1
- package/package.json +1 -1
- package/source/ucumLhcUtils.js +2 -2
- package/source/ucumXmlDocument.js +5 -2
- package/source/unit.js +2 -1
- package/source/unitString.js +142 -130
- package/source-cjs/config.js +1 -12
- package/source-cjs/config.js.map +1 -1
- package/source-cjs/dimension.js +20 -63
- package/source-cjs/dimension.js.map +1 -1
- package/source-cjs/jsonArrayPack.js +7 -25
- package/source-cjs/jsonArrayPack.js.map +1 -1
- package/source-cjs/prefix.js +12 -26
- package/source-cjs/prefix.js.map +1 -1
- package/source-cjs/prefixTables.js +10 -24
- package/source-cjs/prefixTables.js.map +1 -1
- package/source-cjs/ucumFunctions.js +35 -32
- package/source-cjs/ucumFunctions.js.map +1 -1
- package/source-cjs/ucumInternalUtils.js +5 -13
- package/source-cjs/ucumInternalUtils.js.map +1 -1
- package/source-cjs/ucumJsonDefs.js +1 -16
- package/source-cjs/ucumJsonDefs.js.map +1 -1
- package/source-cjs/ucumLhcUtils.js +28 -92
- package/source-cjs/ucumLhcUtils.js.map +1 -1
- package/source-cjs/ucumPkg.js +1 -6
- package/source-cjs/ucumPkg.js.map +1 -1
- package/source-cjs/ucumXmlDocument.js +162 -184
- package/source-cjs/ucumXmlDocument.js.map +1 -1
- package/source-cjs/unit.js +97 -181
- package/source-cjs/unit.js.map +1 -1
- package/source-cjs/unitString.js +521 -608
- package/source-cjs/unitString.js.map +1 -1
- package/source-cjs/unitTables.js +33 -139
- package/source-cjs/unitTables.js.map +1 -1
package/source-cjs/unitString.js
CHANGED
|
@@ -4,26 +4,18 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.UnitString = void 0;
|
|
7
|
-
|
|
8
7
|
var intUtils_ = _interopRequireWildcard(require("./ucumInternalUtils.js"));
|
|
9
|
-
|
|
10
8
|
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|
11
|
-
|
|
12
9
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
13
|
-
|
|
14
10
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
15
|
-
|
|
16
11
|
/**
|
|
17
12
|
* This class handles the parsing of a unit string into a unit object
|
|
18
13
|
*/
|
|
19
|
-
var Ucum = require('./config.js').Ucum;
|
|
20
14
|
|
|
15
|
+
var Ucum = require('./config.js').Ucum;
|
|
21
16
|
var Unit = require('./unit.js').Unit;
|
|
22
|
-
|
|
23
17
|
var UnitTables = require('./unitTables.js').UnitTables;
|
|
24
|
-
|
|
25
18
|
var PrefixTables = require('./prefixTables.js').PrefixTables;
|
|
26
|
-
|
|
27
19
|
class UnitString {
|
|
28
20
|
/**
|
|
29
21
|
* Constructor
|
|
@@ -31,43 +23,52 @@ class UnitString {
|
|
|
31
23
|
constructor() {
|
|
32
24
|
// Get instances of the unit and prefix tables and the utilities
|
|
33
25
|
this.utabs_ = UnitTables.getInstance();
|
|
34
|
-
this.pfxTabs_ = PrefixTables.getInstance();
|
|
26
|
+
this.pfxTabs_ = PrefixTables.getInstance();
|
|
27
|
+
|
|
28
|
+
// Set emphasis characters to defaults. These are used to emphasize
|
|
35
29
|
// certain characters or strings in user messages. They can be reset in
|
|
36
30
|
// the useHTMLInMessages method.
|
|
37
|
-
|
|
38
31
|
this.openEmph_ = Ucum.openEmph_;
|
|
39
|
-
this.closeEmph_ = Ucum.closeEmph_;
|
|
32
|
+
this.closeEmph_ = Ucum.closeEmph_;
|
|
33
|
+
|
|
34
|
+
// Set the braces message to blank. This message is displayed for each
|
|
40
35
|
// validation request on the web page, but is included separately as
|
|
41
36
|
// a note on the validation spreadsheet. The useBraceMsgForEachString
|
|
42
37
|
// method should be used to set the message to be displayed for each
|
|
43
38
|
// unit string.
|
|
39
|
+
this.bracesMsg_ = '';
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
// Set the flags used, with indices, as place holders in unit strings
|
|
46
42
|
// for parenthetical strings and strings within braces.
|
|
47
|
-
|
|
48
43
|
this.parensFlag_ = "parens_placeholder"; // in lieu of Jehoshaphat
|
|
49
|
-
|
|
50
44
|
this.pFlagLen_ = this.parensFlag_.length;
|
|
51
45
|
this.braceFlag_ = "braces_placeholder"; // in lieu of Nebuchadnezzar
|
|
46
|
+
this.bFlagLen_ = this.braceFlag_.length;
|
|
52
47
|
|
|
53
|
-
|
|
48
|
+
// Initialize the message start/end strings, which will be set when
|
|
54
49
|
// parseString is called.
|
|
55
|
-
|
|
56
50
|
this.vcMsgStart_ = null;
|
|
57
|
-
this.vcMsgEnd_ = null;
|
|
51
|
+
this.vcMsgEnd_ = null;
|
|
52
|
+
|
|
53
|
+
// Arrays used by multiple methods within this class to hold persistent
|
|
58
54
|
// data. Just gets too bulky to pass these guys around.
|
|
59
|
-
// Messages to be returned to the calling function
|
|
60
55
|
|
|
61
|
-
|
|
56
|
+
// Messages to be returned to the calling function
|
|
57
|
+
this.retMsg_ = [];
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
// Units for parenthetical unit strings
|
|
60
|
+
this.parensUnits_ = [];
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
// annotation text for annotations found in unit strings
|
|
63
|
+
this.annotations_ = [];
|
|
66
64
|
|
|
65
|
+
// suggestions for unit strings that for which no unit was found
|
|
67
66
|
this.suggestions = [];
|
|
68
67
|
} // end constructor
|
|
68
|
+
|
|
69
69
|
// The start of an error message about an invalid annotation character.
|
|
70
70
|
|
|
71
|
+
// A regular expression for validating annotation strings.
|
|
71
72
|
|
|
72
73
|
/**
|
|
73
74
|
* Sets the emphasis strings to the HTML used in the webpage display - or
|
|
@@ -93,11 +94,10 @@ class UnitString {
|
|
|
93
94
|
* @param use flag indicating whether or not to use the braces message;
|
|
94
95
|
* defaults to true
|
|
95
96
|
*/
|
|
96
|
-
|
|
97
|
-
|
|
98
97
|
useBraceMsgForEachString(use) {
|
|
99
98
|
if (use === undefined || use) this.bracesMsg_ = Ucum.bracesMsg_;else this.bracesMsg_ = '';
|
|
100
99
|
}
|
|
100
|
+
|
|
101
101
|
/**
|
|
102
102
|
* Parses a unit string, returns a unit, a possibly updated version of
|
|
103
103
|
* the string passed in, and messages and suggestions where appropriate.
|
|
@@ -136,15 +136,12 @@ class UnitString {
|
|
|
136
136
|
* was found or if suggestions were not requested.
|
|
137
137
|
* @throws an error if nothing was specified.
|
|
138
138
|
*/
|
|
139
|
-
|
|
140
|
-
|
|
141
139
|
parseString(uStr, valConv, suggest) {
|
|
142
|
-
uStr = uStr.trim();
|
|
143
|
-
|
|
140
|
+
uStr = uStr.trim();
|
|
141
|
+
// Make sure we have something to work with
|
|
144
142
|
if (uStr === '' || uStr === null) {
|
|
145
143
|
throw new Error('Please specify a unit expression to be validated.');
|
|
146
144
|
}
|
|
147
|
-
|
|
148
145
|
if (valConv === 'validate') {
|
|
149
146
|
this.vcMsgStart_ = Ucum.valMsgStart_;
|
|
150
147
|
this.vcMsgEnd_ = Ucum.valMsgEnd_;
|
|
@@ -152,18 +149,18 @@ class UnitString {
|
|
|
152
149
|
this.vcMsgStart_ = Ucum.cnvMsgStart_;
|
|
153
150
|
this.vcMsgEnd_ = Ucum.cnvMsgEnd_;
|
|
154
151
|
}
|
|
155
|
-
|
|
156
152
|
if (suggest === undefined || suggest === false) {
|
|
157
153
|
this.suggestions_ = null;
|
|
158
154
|
} else {
|
|
159
155
|
this.suggestions_ = [];
|
|
160
156
|
}
|
|
161
|
-
|
|
162
157
|
this.retMsg_ = [];
|
|
163
158
|
this.parensUnits_ = [];
|
|
164
159
|
this.annotations_ = [];
|
|
165
160
|
let origString = uStr;
|
|
166
|
-
let retObj = [];
|
|
161
|
+
let retObj = [];
|
|
162
|
+
|
|
163
|
+
// Extract any annotations, i.e., text enclosed in braces ({}) from the
|
|
167
164
|
// string before further processing. Store each one in this.annotations_
|
|
168
165
|
// array and put a placeholder in the string for the annotation. Do
|
|
169
166
|
// this before other processing in case an annotation contains characters
|
|
@@ -171,41 +168,40 @@ class UnitString {
|
|
|
171
168
|
// subsequent processing.
|
|
172
169
|
|
|
173
170
|
uStr = this._getAnnotations(uStr);
|
|
174
|
-
|
|
175
171
|
if (this.retMsg_.length > 0) {
|
|
176
172
|
retObj[0] = null;
|
|
177
173
|
retObj[1] = null;
|
|
178
174
|
} else {
|
|
179
175
|
// Flag used to block further processing on an unrecoverable error
|
|
180
|
-
let endProcessing = this.retMsg_.length > 0;
|
|
176
|
+
let endProcessing = this.retMsg_.length > 0;
|
|
177
|
+
|
|
178
|
+
// First check for one of the "special" units. If it's one of those, put
|
|
181
179
|
// in a substitution phrase for it to avoid having it separated on its
|
|
182
180
|
// embedded operator. This will only happen, by the way, if it is
|
|
183
181
|
// preceded by a prefix or followed by an operator and another unit.
|
|
184
|
-
|
|
185
182
|
let sUnit = null;
|
|
186
|
-
|
|
187
183
|
for (sUnit in Ucum.specUnits_) {
|
|
188
184
|
while (uStr.indexOf(sUnit) !== -1) uStr = uStr.replace(sUnit, Ucum.specUnits_[sUnit]);
|
|
189
|
-
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for spaces and throw an error if any are found. The spec
|
|
190
188
|
// explicitly forbids spaces except in annotations, which is why any
|
|
191
189
|
// annotations are extracted before this check is made.
|
|
192
|
-
|
|
193
|
-
|
|
194
190
|
if (uStr.indexOf(' ') > -1) {
|
|
195
191
|
throw new Error('Blank spaces are not allowed in unit expressions.');
|
|
196
192
|
} // end if blanks were found in the string
|
|
193
|
+
|
|
197
194
|
// assign the array returned to retObj. It will contain 2 elements:
|
|
198
195
|
// the unit returned in position 0; and the origString (possibly
|
|
199
196
|
// modified) in position 1. The origString in position 1 will not
|
|
200
197
|
// be changed by subsequent processing.
|
|
201
|
-
|
|
202
|
-
|
|
203
198
|
retObj = this._parseTheString(uStr, origString);
|
|
204
|
-
let finalUnit = retObj[0];
|
|
199
|
+
let finalUnit = retObj[0];
|
|
200
|
+
|
|
201
|
+
// Do a final check to make sure that finalUnit is a unit and not
|
|
205
202
|
// just a number. Something like "8/{HCP}" will return a "unit" of 8
|
|
206
203
|
// - which is not a unit. Hm - evidently it is. So just create a unit
|
|
207
204
|
// object for it.
|
|
208
|
-
|
|
209
205
|
if (intUtils_.isIntegerUnit(finalUnit) || typeof finalUnit === 'number') {
|
|
210
206
|
finalUnit = new Unit({
|
|
211
207
|
'csCode_': origString,
|
|
@@ -215,10 +211,8 @@ class UnitString {
|
|
|
215
211
|
});
|
|
216
212
|
retObj[0] = finalUnit;
|
|
217
213
|
} // end final check
|
|
218
|
-
|
|
219
214
|
} // end if no annotation errors were found
|
|
220
215
|
|
|
221
|
-
|
|
222
216
|
retObj[2] = this.retMsg_;
|
|
223
217
|
if (this.suggestions_ && this.suggestions_.length > 0) retObj[3] = this.suggestions_;
|
|
224
218
|
return retObj;
|
|
@@ -251,86 +245,83 @@ class UnitString {
|
|
|
251
245
|
* the this.suggestions_ array may be populated by methods called within
|
|
252
246
|
* this one
|
|
253
247
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
256
248
|
_parseTheString(uStr, origString) {
|
|
257
249
|
// Unit to be returned
|
|
258
|
-
let finalUnit = null;
|
|
250
|
+
let finalUnit = null;
|
|
251
|
+
|
|
252
|
+
// Flag used to block further processing on an unrecoverable error
|
|
253
|
+
let endProcessing = this.retMsg_.length > 0;
|
|
259
254
|
|
|
260
|
-
|
|
255
|
+
// Call _processParens to search for and process any/all parenthetical
|
|
261
256
|
// strings in uStr. Units created for parenthetical strings will be
|
|
262
257
|
// stored in the this.parensUnits_ array.
|
|
263
|
-
|
|
264
258
|
let parensResp = this._processParens(uStr, origString);
|
|
259
|
+
endProcessing = parensResp[2];
|
|
265
260
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
let uArray = []; // Continue if we didn't hit a problem
|
|
261
|
+
// The array used to hold the units and their operators.
|
|
262
|
+
let uArray = [];
|
|
269
263
|
|
|
264
|
+
// Continue if we didn't hit a problem
|
|
270
265
|
if (!endProcessing) {
|
|
271
266
|
uStr = parensResp[0];
|
|
272
|
-
origString = parensResp[1];
|
|
273
|
-
// descriptors with operators.
|
|
267
|
+
origString = parensResp[1];
|
|
274
268
|
|
|
269
|
+
// Call _makeUnitsArray to convert the string to an array of unit
|
|
270
|
+
// descriptors with operators.
|
|
275
271
|
let mkUArray = this._makeUnitsArray(uStr, origString);
|
|
276
|
-
|
|
277
272
|
endProcessing = mkUArray[2];
|
|
278
|
-
|
|
279
273
|
if (!endProcessing) {
|
|
280
274
|
uArray = mkUArray[0];
|
|
281
|
-
origString = mkUArray[1];
|
|
282
|
-
|
|
275
|
+
origString = mkUArray[1];
|
|
276
|
+
// Create a unit object out of each un element
|
|
283
277
|
let uLen = uArray.length;
|
|
284
|
-
|
|
285
278
|
for (let u1 = 0; u1 < uLen; u1++) {
|
|
286
279
|
//for (let u1 = 0; u1 < uLen && !endProcessing; u1++) {
|
|
287
|
-
let curCode = uArray[u1]['un'];
|
|
280
|
+
let curCode = uArray[u1]['un'];
|
|
281
|
+
|
|
282
|
+
// Determine the type of the "un" attribute of the current array element
|
|
283
|
+
|
|
288
284
|
// Check to see if it's a number. If so write the number version of
|
|
289
285
|
// the number back to the "un" attribute and move on
|
|
290
|
-
|
|
291
286
|
if (intUtils_.isIntegerUnit(curCode)) {
|
|
292
287
|
uArray[u1]['un'] = Number(curCode);
|
|
293
288
|
} else {
|
|
294
289
|
// The current unit array element is a string. Check now to see
|
|
295
290
|
// if it is or contains a parenthesized unit from this.parensUnits_.
|
|
296
291
|
// If so, call _getParens to process the string and get the unit.
|
|
292
|
+
|
|
297
293
|
if (curCode.indexOf(this.parensFlag_) >= 0) {
|
|
298
|
-
let parenUnit = this._getParensUnit(curCode, origString);
|
|
294
|
+
let parenUnit = this._getParensUnit(curCode, origString);
|
|
295
|
+
// if we couldn't process the string, set the end flag and bypass
|
|
299
296
|
// further processing.
|
|
297
|
+
if (!endProcessing) endProcessing = parenUnit[1];
|
|
300
298
|
|
|
301
|
-
|
|
302
|
-
if (!endProcessing) endProcessing = parenUnit[1]; // If we're good, put the unit in the uArray and replace the
|
|
299
|
+
// If we're good, put the unit in the uArray and replace the
|
|
303
300
|
// curCode, which contains the parentheses placeholders, etc.,
|
|
304
301
|
// with the unit's code - including any substitutions.
|
|
305
|
-
|
|
306
302
|
if (!endProcessing) {
|
|
307
303
|
uArray[u1]['un'] = parenUnit[0];
|
|
308
304
|
}
|
|
309
305
|
} // end if the curCode contains a parenthesized unit
|
|
306
|
+
|
|
310
307
|
// Else it's not a parenthetical unit and not a number. Call
|
|
311
308
|
// _makeUnit to create a unit for it.
|
|
312
309
|
else {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
} // end if the curCode is not a parenthetical expression
|
|
323
|
-
|
|
310
|
+
let uRet = this._makeUnit(curCode, origString);
|
|
311
|
+
// If we didn't get a unit, set the endProcessing flag.
|
|
312
|
+
if (uRet[0] === null) {
|
|
313
|
+
endProcessing = true;
|
|
314
|
+
} else {
|
|
315
|
+
uArray[u1]['un'] = uRet[0];
|
|
316
|
+
origString = uRet[1];
|
|
317
|
+
}
|
|
318
|
+
} // end if the curCode is not a parenthetical expression
|
|
324
319
|
} // end if the "un" array is a not a number
|
|
325
|
-
|
|
326
320
|
} // end do for each element in the units array
|
|
327
|
-
|
|
328
321
|
} // end if _makeUnitsArray did not return an error
|
|
329
|
-
|
|
330
322
|
} // end if _processParens did not find an error that causes a stop
|
|
331
|
-
// If we're still good, continue
|
|
332
|
-
|
|
333
323
|
|
|
324
|
+
// If we're still good, continue
|
|
334
325
|
if (!endProcessing) {
|
|
335
326
|
// Process the units (and numbers) to create one final unit object
|
|
336
327
|
if ((uArray[0] === null || uArray[0] === ' ' || uArray[0]['un'] === undefined || uArray[0]['un'] === null) && this.retMsg_.length === 0) {
|
|
@@ -339,11 +330,9 @@ class UnitString {
|
|
|
339
330
|
endProcessing = true;
|
|
340
331
|
}
|
|
341
332
|
}
|
|
342
|
-
|
|
343
333
|
if (!endProcessing) {
|
|
344
334
|
finalUnit = this._performUnitArithmetic(uArray, origString);
|
|
345
335
|
}
|
|
346
|
-
|
|
347
336
|
return [finalUnit, origString];
|
|
348
337
|
} // end _parseTheString
|
|
349
338
|
|
|
@@ -360,20 +349,16 @@ class UnitString {
|
|
|
360
349
|
* (informational, error or warning) generated by this or called methods
|
|
361
350
|
* the this.annotations_ array is populated by this method
|
|
362
351
|
*/
|
|
363
|
-
|
|
364
|
-
|
|
365
352
|
_getAnnotations(uString) {
|
|
366
353
|
let openBrace = uString.indexOf('{');
|
|
367
|
-
|
|
368
354
|
while (openBrace >= 0) {
|
|
369
355
|
let closeBrace = uString.indexOf('}');
|
|
370
|
-
|
|
371
356
|
if (closeBrace < 0) {
|
|
372
357
|
this.retMsg_.push('Missing closing brace for annotation starting at ' + this.openEmph_ + uString.substr(openBrace) + this.closeEmph_);
|
|
373
358
|
openBrace = -1;
|
|
374
359
|
} else {
|
|
375
|
-
let braceStr = uString.substring(openBrace, closeBrace + 1);
|
|
376
|
-
|
|
360
|
+
let braceStr = uString.substring(openBrace, closeBrace + 1);
|
|
361
|
+
// Check for valid characters in the annotation.
|
|
377
362
|
if (!UnitString.VALID_ANNOTATION_REGEX.test(braceStr)) {
|
|
378
363
|
this.retMsg_.push(UnitString.INVALID_ANNOTATION_CHAR_MSG + this.openEmph_ + braceStr + this.closeEmph_);
|
|
379
364
|
openBrace = -1; // end search for annotations
|
|
@@ -385,15 +370,13 @@ class UnitString {
|
|
|
385
370
|
}
|
|
386
371
|
}
|
|
387
372
|
} // end do while we have an opening brace
|
|
388
|
-
// check for a stray/unmatched closing brace
|
|
389
|
-
|
|
390
373
|
|
|
374
|
+
// check for a stray/unmatched closing brace
|
|
391
375
|
if (this.retMsg_.length == 0) {
|
|
392
376
|
// if there were no other errors above
|
|
393
377
|
let closeBrace = uString.indexOf('}');
|
|
394
378
|
if (closeBrace >= 0) this.retMsg_.push('Missing opening brace for closing brace found at ' + this.openEmph_ + uString.substring(0, closeBrace + 1) + this.closeEmph_);
|
|
395
379
|
}
|
|
396
|
-
|
|
397
380
|
return uString;
|
|
398
381
|
} // end _getAnnotations
|
|
399
382
|
|
|
@@ -427,108 +410,101 @@ class UnitString {
|
|
|
427
410
|
* this this.parensUnits_ array will be populated with units found for
|
|
428
411
|
* parenthetical unit strings
|
|
429
412
|
*/
|
|
430
|
-
|
|
431
|
-
|
|
432
413
|
_processParens(uString, origString) {
|
|
433
414
|
// Unit strings array and index
|
|
434
415
|
let uStrArray = [];
|
|
435
416
|
let uStrAryPos = 0;
|
|
436
417
|
let stopProcessing = false;
|
|
437
|
-
let pu = this.parensUnits_.length;
|
|
418
|
+
let pu = this.parensUnits_.length;
|
|
419
|
+
|
|
420
|
+
// Count of characters trimmed off the beginning of the unit string (uString)
|
|
438
421
|
// as units are removed from it; used for error messages to provide
|
|
439
422
|
// context.
|
|
423
|
+
let trimmedCt = 0;
|
|
440
424
|
|
|
441
|
-
|
|
425
|
+
// Break the unit string into pieces that consist of text outside of
|
|
442
426
|
// parenthetical strings and placeholders for the parenthetical units.
|
|
443
427
|
// This method is called recursively for parenthetical strings and the units
|
|
444
428
|
// returned are stored in the this.parensUnits_ array.
|
|
445
|
-
|
|
446
429
|
while (uString !== "" && !stopProcessing) {
|
|
447
430
|
let openCt = 0;
|
|
448
431
|
let closeCt = 0;
|
|
449
|
-
let openPos = uString.indexOf('(');
|
|
432
|
+
let openPos = uString.indexOf('(');
|
|
433
|
+
|
|
434
|
+
// If an opening parenthesis was not found, check for an unmatched
|
|
450
435
|
// close parenthesis. If one was found report the error and end
|
|
451
436
|
// processing.
|
|
452
|
-
|
|
453
437
|
if (openPos < 0) {
|
|
454
438
|
let closePos = uString.indexOf(')');
|
|
455
|
-
|
|
456
439
|
if (closePos >= 0) {
|
|
457
440
|
let theMsg = `Missing open parenthesis for close ` + `parenthesis at ${uString.substring(0, closePos + trimmedCt)}` + `${this.openEmph_}${uString.substr(closePos, 1)}${this.closeEmph_}`;
|
|
458
|
-
|
|
459
441
|
if (closePos < uString.length - 1) {
|
|
460
442
|
theMsg += `${uString.substr(closePos + 1)}`;
|
|
461
443
|
}
|
|
462
|
-
|
|
463
444
|
this.retMsg_.push(theMsg);
|
|
464
445
|
uStrArray[uStrAryPos] = uString;
|
|
465
446
|
stopProcessing = true;
|
|
466
447
|
} // end if a close parenthesis was found
|
|
448
|
+
|
|
467
449
|
// If no parentheses were found in the current unit string, transfer
|
|
468
450
|
// it to the units array and blank out the string, which will end
|
|
469
451
|
// the search for parenthetical units.
|
|
470
452
|
else {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
453
|
+
uStrArray[uStrAryPos] = uString;
|
|
454
|
+
uString = "";
|
|
455
|
+
} // end if no close parenthesis was found
|
|
475
456
|
} // end if no open parenthesis was found
|
|
457
|
+
|
|
476
458
|
// Otherwise an open parenthesis was found. Process the string that
|
|
477
459
|
// includes the parenthetical group
|
|
478
460
|
else {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
} // Find the matching closePos, i.e., the one that closes the
|
|
486
|
-
// parenthetical group that this one opens. Look also for
|
|
487
|
-
// another open parenthesis, in case this includes nested parenthetical
|
|
488
|
-
// strings. This continues until it finds the same number of close
|
|
489
|
-
// parentheses as open parentheses, or runs out of string to check.
|
|
490
|
-
// In the case of nested parentheses this will identify the outer set
|
|
491
|
-
// of parentheses.
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
let closePos = 0;
|
|
495
|
-
let c = openPos + 1;
|
|
496
|
-
|
|
497
|
-
for (; c < uLen && openCt != closeCt; c++) {
|
|
498
|
-
if (uString[c] === '(') openCt += 1;else if (uString[c] === ')') closeCt += 1;
|
|
499
|
-
} // Put a placeholder for the group in the unit strings array and recursively
|
|
500
|
-
// call this method for the parenthetical group. Put the unit returned
|
|
501
|
-
// in this.parensUnits_. Set the unit string to whatever follows
|
|
502
|
-
// the position of the closing parenthesis for this group, to be
|
|
503
|
-
// processed by the next iteration of this loop. If there's nothing
|
|
504
|
-
// left uString is set to "".
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (openCt === closeCt) {
|
|
508
|
-
closePos = c;
|
|
509
|
-
uStrArray[uStrAryPos++] = this.parensFlag_ + pu.toString() + this.parensFlag_;
|
|
461
|
+
openCt += 1;
|
|
462
|
+
// Write the text before the parentheses (if any) to the unit strings array
|
|
463
|
+
let uLen = uString.length;
|
|
464
|
+
if (openPos > 0) {
|
|
465
|
+
uStrArray[uStrAryPos++] = uString.substr(0, openPos);
|
|
466
|
+
}
|
|
510
467
|
|
|
511
|
-
|
|
468
|
+
// Find the matching closePos, i.e., the one that closes the
|
|
469
|
+
// parenthetical group that this one opens. Look also for
|
|
470
|
+
// another open parenthesis, in case this includes nested parenthetical
|
|
471
|
+
// strings. This continues until it finds the same number of close
|
|
472
|
+
// parentheses as open parentheses, or runs out of string to check.
|
|
473
|
+
// In the case of nested parentheses this will identify the outer set
|
|
474
|
+
// of parentheses.
|
|
475
|
+
let closePos = 0;
|
|
476
|
+
let c = openPos + 1;
|
|
477
|
+
for (; c < uLen && openCt != closeCt; c++) {
|
|
478
|
+
if (uString[c] === '(') openCt += 1;else if (uString[c] === ')') closeCt += 1;
|
|
479
|
+
}
|
|
512
480
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
481
|
+
// Put a placeholder for the group in the unit strings array and recursively
|
|
482
|
+
// call this method for the parenthetical group. Put the unit returned
|
|
483
|
+
// in this.parensUnits_. Set the unit string to whatever follows
|
|
484
|
+
// the position of the closing parenthesis for this group, to be
|
|
485
|
+
// processed by the next iteration of this loop. If there's nothing
|
|
486
|
+
// left uString is set to "".
|
|
487
|
+
if (openCt === closeCt) {
|
|
488
|
+
closePos = c;
|
|
489
|
+
uStrArray[uStrAryPos++] = this.parensFlag_ + pu.toString() + this.parensFlag_;
|
|
490
|
+
let parseResp = this._parseTheString(uString.substring(openPos + 1, closePos - 1), origString);
|
|
491
|
+
if (parseResp[0] === null) stopProcessing = true;else {
|
|
492
|
+
origString = parseResp[1];
|
|
493
|
+
this.parensUnits_[pu++] = parseResp[0];
|
|
494
|
+
uString = uString.substr(closePos);
|
|
495
|
+
trimmedCt = closePos;
|
|
496
|
+
}
|
|
497
|
+
} // end if the number of open and close parentheses matched
|
|
528
498
|
|
|
499
|
+
// If the number of open and close parentheses doesn't match, indicate
|
|
500
|
+
// an error.
|
|
501
|
+
else {
|
|
502
|
+
uStrArray.push(origString.substr(openPos));
|
|
503
|
+
this.retMsg_.push(`Missing close parenthesis for open parenthesis at ` + `${origString.substring(0, openPos + trimmedCt)}` + `${this.openEmph_}${origString.substr(openPos, 1)}` + `${this.closeEmph_}${origString.substr(openPos + 1)}`);
|
|
504
|
+
stopProcessing = true;
|
|
505
|
+
}
|
|
506
|
+
} // end if an open parenthesis was found
|
|
529
507
|
} // end do while the input string is not empty
|
|
530
|
-
|
|
531
|
-
|
|
532
508
|
if (stopProcessing) this.parensUnits_ = [];
|
|
533
509
|
return [uStrArray.join(''), origString, stopProcessing];
|
|
534
510
|
} // end _processParens
|
|
@@ -552,47 +528,44 @@ class UnitString {
|
|
|
552
528
|
* the this.retMsg_ array will be updated with any user messages
|
|
553
529
|
* (informational, error or warning) generated by this or called methods
|
|
554
530
|
*/
|
|
555
|
-
|
|
556
|
-
|
|
557
531
|
_makeUnitsArray(uStr, origString) {
|
|
558
532
|
// Separate the string into pieces based on delimiters / (division) and .
|
|
559
533
|
// (multiplication). The idea is to get an array of units on which we
|
|
560
534
|
// can then perform any operations (prefixes, multiplication, division).
|
|
535
|
+
|
|
561
536
|
let uArray1 = uStr.match(/([./]|[^./]+)/g);
|
|
562
537
|
let endProcessing = false;
|
|
563
538
|
let uArray = [];
|
|
564
|
-
let startNumCheck = /(^[0-9]+)(\[?[a-zA-Z\_0-9a-zA-Z\_]+\]?$)/;
|
|
539
|
+
let startNumCheck = /(^[0-9]+)(\[?[a-zA-Z\_0-9a-zA-Z\_]+\]?$)/;
|
|
540
|
+
|
|
541
|
+
// If the first element in the array is the division operator (/), the
|
|
565
542
|
// string started with '/'. Add a first element containing 1 to the
|
|
566
543
|
// array, which will cause the correct computation to be performed (inversion).
|
|
567
|
-
|
|
568
544
|
if (uArray1[0] === "/") {
|
|
569
545
|
uArray1.unshift("1");
|
|
570
|
-
}
|
|
546
|
+
}
|
|
547
|
+
// If the first element in the array is the multiplication operator (.)
|
|
571
548
|
// return an error.
|
|
572
549
|
else if (uArray1[0] === '.') {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
550
|
+
this.retMsg_.push(`${origString} is not a valid UCUM code. ` + `The multiplication operator at the beginning of the expression is ` + `not valid. A multiplication operator must appear only between ` + `two codes.`);
|
|
551
|
+
endProcessing = true;
|
|
552
|
+
}
|
|
577
553
|
if (!endProcessing) {
|
|
578
554
|
// Check to see if there is a number preceding a unit code, e.g., 2mg
|
|
579
555
|
// If so, update the first element to remove the number (2mg -> mg) and
|
|
580
556
|
// add two elements to the beginning of the array - the number and the
|
|
581
557
|
// multiplication operator.
|
|
558
|
+
|
|
582
559
|
if (!intUtils_.isNumericString(uArray1[0])) {
|
|
583
560
|
let numRes = uArray1[0].match(startNumCheck);
|
|
584
|
-
|
|
585
561
|
if (numRes && numRes.length === 3 && numRes[1] !== '' && numRes[2] !== '' && numRes[2].indexOf(this.braceFlag_) !== 0) {
|
|
586
562
|
let dispVal = numRes[2];
|
|
587
|
-
|
|
588
563
|
if (!endProcessing && numRes[2].indexOf(this.parensFlag_) !== -1) {
|
|
589
564
|
let parensback = this._getParensUnit(numRes[2], origString);
|
|
590
|
-
|
|
591
565
|
numRes[2] = parensback[0]['csCode_'];
|
|
592
566
|
dispVal = `(${numRes[2]})`;
|
|
593
567
|
endProcessing = parensback[1];
|
|
594
568
|
}
|
|
595
|
-
|
|
596
569
|
if (!endProcessing) {
|
|
597
570
|
this.retMsg_.push(`${numRes[1]}${dispVal} is not a valid UCUM code.` + ` ${this.vcMsgStart_}${numRes[1]}.${dispVal}${this.vcMsgEnd_}`);
|
|
598
571
|
origString = origString.replace(`${numRes[1]}${dispVal}`, `${numRes[1]}.${dispVal}`);
|
|
@@ -601,6 +574,7 @@ class UnitString {
|
|
|
601
574
|
}
|
|
602
575
|
}
|
|
603
576
|
} // end if the first element is not a number (only)
|
|
577
|
+
|
|
604
578
|
// Create an array of unit/operator objects. The unit is, for now, the
|
|
605
579
|
// string containing the unit code (e.g., Hz for hertz) including
|
|
606
580
|
// a possible prefix and exponent. The operator is the operator to be
|
|
@@ -608,21 +582,18 @@ class UnitString {
|
|
|
608
582
|
// us two objects. The first will have a unit of a, and a blank operator
|
|
609
583
|
// (because it's the first unit). The second would have a unit of b
|
|
610
584
|
// and the multiplication operator (.).
|
|
611
|
-
|
|
612
|
-
|
|
613
585
|
if (!endProcessing) {
|
|
614
586
|
let u1 = uArray1.length;
|
|
615
587
|
uArray = [{
|
|
616
588
|
op: "",
|
|
617
589
|
un: uArray1[0]
|
|
618
590
|
}];
|
|
619
|
-
|
|
620
591
|
for (let n = 1; n < u1; n++) {
|
|
621
592
|
// check to make sure that we don't have two operators together, e.g.,
|
|
622
593
|
// mg./K. If so, let the user know the problem.
|
|
623
|
-
let theOp = uArray1[n++];
|
|
594
|
+
let theOp = uArray1[n++];
|
|
595
|
+
// oh wait - check to make sure something is even there, that the
|
|
624
596
|
// user didn't end the expression with an operator.
|
|
625
|
-
|
|
626
597
|
if (!uArray1[n]) {
|
|
627
598
|
this.retMsg_.push(`${origString} is not a valid UCUM code. ` + `It is terminated with the operator ${this.openEmph_}` + `${theOp}${this.closeEmph_}.`);
|
|
628
599
|
n = u1;
|
|
@@ -642,63 +613,52 @@ class UnitString {
|
|
|
642
613
|
// 2.kJ.
|
|
643
614
|
if (!intUtils_.isNumericString(uArray1[n])) {
|
|
644
615
|
let numRes2 = uArray1[n].match(startNumCheck);
|
|
645
|
-
|
|
646
616
|
if (numRes2 && numRes2.length === 3 && numRes2[1] !== '' && numRes2[2] !== '' && numRes2[2].indexOf(this.braceFlag_) !== 0) {
|
|
647
617
|
let invalidString = numRes2[0];
|
|
648
|
-
|
|
649
618
|
if (!endProcessing && numRes2[2].indexOf(this.parensFlag_) !== -1) {
|
|
650
619
|
let parensback = this._getParensUnit(numRes2[2], origString);
|
|
651
|
-
|
|
652
620
|
numRes2[2] = parensback[0]['csCode_'];
|
|
653
621
|
invalidString = `(${numRes2[2]})`;
|
|
654
622
|
endProcessing = parensback[1];
|
|
655
|
-
|
|
656
623
|
if (!endProcessing) {
|
|
657
624
|
this.retMsg_.push(`${numRes2[1]}${invalidString} is not a ` + `valid UCUM code. ${this.vcMsgStart_}${numRes2[1]}.${invalidString}` + `${this.vcMsgEnd_}`);
|
|
658
625
|
let parensString = `(${numRes2[1]}.${invalidString})`;
|
|
659
626
|
origString = origString.replace(`${numRes2[1]}${invalidString}`, parensString);
|
|
660
|
-
|
|
661
627
|
let nextParens = this._processParens(parensString, origString);
|
|
662
|
-
|
|
663
628
|
endProcessing = nextParens[2];
|
|
664
|
-
|
|
665
629
|
if (!endProcessing) {
|
|
666
630
|
uArray.push({
|
|
667
631
|
op: theOp,
|
|
668
632
|
un: nextParens[0]
|
|
669
633
|
});
|
|
670
|
-
}
|
|
671
|
-
|
|
634
|
+
}
|
|
635
|
+
//uArray.push({op: '.', un: numRes2[2]});
|
|
672
636
|
}
|
|
673
637
|
} // end if the string represents a parenthesized unit
|
|
674
638
|
else {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
} // end if no error on the processParens call
|
|
692
|
-
|
|
693
|
-
} // end if the string does not represent a parenthesized unit
|
|
694
|
-
|
|
639
|
+
let parensStr = '(' + numRes2[1] + '.' + numRes2[2] + ')';
|
|
640
|
+
let parensResp = this._processParens(parensStr, origString);
|
|
641
|
+
// if a "stop processing" flag was returned, set the n index to end
|
|
642
|
+
// the loop and set the endProcessing flag
|
|
643
|
+
if (parensResp[2]) {
|
|
644
|
+
n = u1;
|
|
645
|
+
endProcessing = true;
|
|
646
|
+
} else {
|
|
647
|
+
this.retMsg_.push(`${numRes2[0]} is not a ` + `valid UCUM code. ${this.vcMsgStart_}${numRes2[1]}.${numRes2[2]}` + `${this.vcMsgEnd_}`);
|
|
648
|
+
origString = origString.replace(numRes2[0], parensStr);
|
|
649
|
+
uArray.push({
|
|
650
|
+
op: theOp,
|
|
651
|
+
un: parensResp[0]
|
|
652
|
+
});
|
|
653
|
+
} // end if no error on the processParens call
|
|
654
|
+
} // end if the string does not represent a parenthesized unit
|
|
695
655
|
} // end if the string is a number followed by a string
|
|
696
656
|
else {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
657
|
+
uArray.push({
|
|
658
|
+
op: theOp,
|
|
659
|
+
un: uArray1[n]
|
|
660
|
+
});
|
|
661
|
+
}
|
|
702
662
|
} else {
|
|
703
663
|
uArray.push({
|
|
704
664
|
op: theOp,
|
|
@@ -706,14 +666,9 @@ class UnitString {
|
|
|
706
666
|
});
|
|
707
667
|
}
|
|
708
668
|
} // end if there isn't a missing operator or unit code
|
|
709
|
-
|
|
710
669
|
} // end do for each element in uArray1
|
|
711
|
-
|
|
712
670
|
} // end if a processing error didn't occur in getParensUnit
|
|
713
|
-
|
|
714
671
|
} // end if the string did not begin with a '.' with no following digit
|
|
715
|
-
|
|
716
|
-
|
|
717
672
|
return [uArray, origString, endProcessing];
|
|
718
673
|
} // end _makeUnitsArray
|
|
719
674
|
|
|
@@ -745,53 +700,50 @@ class UnitString {
|
|
|
745
700
|
* @throws an error if an invalid parensUnit index was found. This is
|
|
746
701
|
* a processing error.
|
|
747
702
|
*/
|
|
748
|
-
|
|
749
|
-
|
|
750
703
|
_getParensUnit(pStr, origString) {
|
|
751
704
|
let endProcessing = false;
|
|
752
705
|
let retAry = [];
|
|
753
706
|
let retUnit = null;
|
|
754
707
|
let befAnnoText = null;
|
|
755
|
-
let aftAnnoText = null;
|
|
708
|
+
let aftAnnoText = null;
|
|
709
|
+
|
|
710
|
+
// Get the location of the flags. We're assuming there are only two
|
|
756
711
|
// because _processParens takes care of nesting. By the time we get
|
|
757
712
|
// here we should not be looking a nested parens. Also get any text
|
|
758
713
|
// before and after the parentheses. Once we get the unit we update
|
|
759
714
|
// the input string with the unit's csCode_, which will wipe out any
|
|
760
715
|
// before and after text
|
|
761
|
-
|
|
762
716
|
let psIdx = pStr.indexOf(this.parensFlag_);
|
|
763
717
|
let befText = null;
|
|
764
|
-
|
|
765
718
|
if (psIdx > 0) {
|
|
766
719
|
befText = pStr.substr(0, psIdx - 1);
|
|
767
720
|
}
|
|
768
|
-
|
|
769
721
|
let peIdx = pStr.lastIndexOf(this.parensFlag_);
|
|
770
722
|
let aftText = null;
|
|
771
|
-
|
|
772
723
|
if (peIdx + this.pFlagLen_ < pStr.length) {
|
|
773
724
|
aftText = pStr.substr(peIdx + this.pFlagLen_);
|
|
774
|
-
}
|
|
725
|
+
}
|
|
775
726
|
|
|
727
|
+
// Get the text between the flags
|
|
728
|
+
let pNumText = pStr.substring(psIdx + this.pFlagLen_, peIdx);
|
|
776
729
|
|
|
777
|
-
|
|
730
|
+
// Make sure the index is a number, and if it is, get the unit from the
|
|
778
731
|
// this.parensUnits_ array
|
|
779
|
-
|
|
780
732
|
if (intUtils_.isNumericString(pNumText)) {
|
|
781
733
|
retUnit = this.parensUnits_[Number(pNumText)];
|
|
782
|
-
|
|
783
734
|
if (!intUtils_.isIntegerUnit(retUnit)) {
|
|
784
735
|
pStr = retUnit.csCode_;
|
|
785
736
|
} else {
|
|
786
737
|
pStr = retUnit;
|
|
787
738
|
}
|
|
788
|
-
}
|
|
739
|
+
}
|
|
740
|
+
// If it's not a number, it's a programming error. Throw a fit.
|
|
789
741
|
else {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
// see if it's a number or an annotation.
|
|
793
|
-
|
|
742
|
+
throw new Error(`Processing error - invalid parens number ${pNumText} ` + `found in ${pStr}.`);
|
|
743
|
+
}
|
|
794
744
|
|
|
745
|
+
// If there's something in front of the starting parentheses flag, check to
|
|
746
|
+
// see if it's a number or an annotation.
|
|
795
747
|
if (befText) {
|
|
796
748
|
// If it's a number, assume that multiplication was assumed
|
|
797
749
|
if (intUtils_.isNumericString(befText)) {
|
|
@@ -804,81 +756,79 @@ class UnitString {
|
|
|
804
756
|
this.retMsg_.push(`${befText}${pStr} is not a valid UCUM code.\n` + this.vcMsgStart_ + pStr + this.vcMsgEnd_);
|
|
805
757
|
} else {
|
|
806
758
|
if (befText.indexOf(this.braceFlag_) >= 0) {
|
|
807
|
-
let annoRet = this._getAnnoText(befText, origString);
|
|
759
|
+
let annoRet = this._getAnnoText(befText, origString);
|
|
760
|
+
// if we found not only an annotation, but text before or after
|
|
808
761
|
// the annotation (remembering that this is all before the
|
|
809
762
|
// parentheses) throw an error - because we don't know what
|
|
810
763
|
// to do with it. Could it be missing an operator?
|
|
811
|
-
|
|
812
|
-
|
|
813
764
|
if (annoRet[1] || annoRet[2]) {
|
|
814
765
|
throw new Error(`Text found before the parentheses (` + `${befText}) included an annotation along with other text ` + `for parenthetical unit ${retUnit.csCode_}`);
|
|
815
|
-
}
|
|
766
|
+
}
|
|
767
|
+
// Otherwise put the annotation after the unit string and note
|
|
816
768
|
// the misplacement.
|
|
817
|
-
|
|
818
|
-
|
|
819
769
|
pStr += annoRet[0];
|
|
820
770
|
this.retMsg_.push(`The annotation ${annoRet[0]} before the unit ` + `code is invalid.\n` + this.vcMsgStart_ + pStr + this.vcMsgEnd_);
|
|
821
|
-
}
|
|
771
|
+
}
|
|
772
|
+
// else the text before the parentheses is neither a number nor
|
|
822
773
|
// an annotation. If suggestions were NOT requested, record an
|
|
823
774
|
// error.
|
|
824
775
|
else if (!this.suggestions_) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
776
|
+
this.retMsg_.push(`${befText} preceding the unit code ${pStr} ` + `is invalid. Unable to make a substitution.`);
|
|
777
|
+
endProcessing = true;
|
|
778
|
+
}
|
|
779
|
+
// otherwise try for suggestions
|
|
780
|
+
else {
|
|
781
|
+
let suggestStat = this._getSuggestions(befText);
|
|
782
|
+
endProcessing = suggestStat !== 'succeeded';
|
|
783
|
+
} // end if a brace was found or, if not, suggestions were not or
|
|
833
784
|
// were requested
|
|
834
|
-
|
|
835
785
|
} // end if text preceding the parentheses was not a number
|
|
836
|
-
|
|
837
786
|
} // end if there was text before the parentheses
|
|
838
|
-
// Process any text after the parentheses
|
|
839
|
-
|
|
840
787
|
|
|
788
|
+
// Process any text after the parentheses
|
|
841
789
|
if (aftText) {
|
|
842
790
|
// if it's an annotation, get it and add it to the pStr
|
|
843
791
|
if (aftText.indexOf(this.braceFlag_) >= 0) {
|
|
844
|
-
let annoRet = this._getAnnoText(aftText, origString);
|
|
792
|
+
let annoRet = this._getAnnoText(aftText, origString);
|
|
793
|
+
// if we found not only an annotation, but text before or after
|
|
845
794
|
// the annotation (remembering that this is all after the
|
|
846
795
|
// parentheses) throw an error - because we don't know what
|
|
847
796
|
// to do with it. Could it be missing an operator?
|
|
848
|
-
|
|
849
|
-
|
|
850
797
|
if (annoRet[1] || annoRet[2]) {
|
|
851
798
|
throw new Error(`Text found after the parentheses (` + `${aftText}) included an annotation along with other text ` + `for parenthetical unit ${retUnit.csCode_}`);
|
|
852
|
-
}
|
|
799
|
+
}
|
|
800
|
+
// Otherwise put the annotation after the unit string - no message
|
|
853
801
|
// needed.
|
|
854
|
-
|
|
855
|
-
|
|
856
802
|
pStr += annoRet[0];
|
|
857
|
-
}
|
|
803
|
+
}
|
|
804
|
+
// Otherwise check to see if it's an exponent. If so, warn the
|
|
858
805
|
// user that it's not valid - but try it anyway
|
|
859
806
|
else {
|
|
860
|
-
|
|
807
|
+
if (intUtils_.isNumericString(aftText)) {
|
|
808
|
+
retUnit = null;
|
|
809
|
+
let msg = `An exponent (${aftText}) following a parenthesis ` + `is invalid as of revision 1.9 of the UCUM Specification.`;
|
|
810
|
+
// Add the suggestion only if the string in the parenthesis don't end with a number.
|
|
811
|
+
if (!pStr.match(/\d$/)) {
|
|
861
812
|
pStr += aftText;
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
813
|
+
msg += '\n ' + this.vcMsgStart_ + pStr + this.vcMsgEnd_;
|
|
814
|
+
}
|
|
815
|
+
this.retMsg_.push(msg);
|
|
816
|
+
endProcessing = true;
|
|
817
|
+
}
|
|
818
|
+
// else the text after the parentheses is neither a number nor
|
|
819
|
+
// an annotation. If suggestions were NOT requested, record an
|
|
820
|
+
// error.
|
|
821
|
+
else if (!this.suggestions_) {
|
|
822
|
+
this.retMsg_.push(`Text ${aftText} following the unit code ${pStr} ` + `is invalid. Unable to make a substitution.`);
|
|
823
|
+
endProcessing = true;
|
|
824
|
+
}
|
|
825
|
+
// otherwise try for suggestions
|
|
826
|
+
else {
|
|
827
|
+
let suggestStat = this._getSuggestions(befText);
|
|
828
|
+
endProcessing = suggestStat !== 'succeeded';
|
|
829
|
+
} // end if text following the parentheses not an exponent
|
|
830
|
+
} // end if text following the parentheses is not an annotation
|
|
879
831
|
} // end if there is text following the parentheses
|
|
880
|
-
|
|
881
|
-
|
|
882
832
|
if (!endProcessing) {
|
|
883
833
|
if (!retUnit) {
|
|
884
834
|
retUnit = new Unit({
|
|
@@ -896,7 +846,6 @@ class UnitString {
|
|
|
896
846
|
retUnit.csCode_ = pStr;
|
|
897
847
|
}
|
|
898
848
|
}
|
|
899
|
-
|
|
900
849
|
return [retUnit, endProcessing];
|
|
901
850
|
} // end _getParensUnit
|
|
902
851
|
|
|
@@ -922,31 +871,28 @@ class UnitString {
|
|
|
922
871
|
* the this.annotations_ array is used as the source for the annotations text
|
|
923
872
|
* @throws an error if for a processing error - an invalid annotation index.
|
|
924
873
|
*/
|
|
925
|
-
|
|
926
|
-
|
|
927
874
|
_getAnnoText(pStr, origString) {
|
|
928
875
|
// if the starting braces flag is not at index 0, get the starting
|
|
929
876
|
// text and the adjust the pStr to omit it.
|
|
930
877
|
let asIdx = pStr.indexOf(this.braceFlag_);
|
|
931
878
|
let startText = asIdx > 0 ? pStr.substring(0, asIdx) : null;
|
|
932
|
-
|
|
933
879
|
if (asIdx !== 0) {
|
|
934
880
|
pStr = pStr.substr(asIdx);
|
|
935
|
-
}
|
|
936
|
-
|
|
881
|
+
}
|
|
937
882
|
|
|
883
|
+
// Get the location of the end flag and, if text follows it, get the text
|
|
938
884
|
let aeIdx = pStr.indexOf(this.braceFlag_, 1);
|
|
939
|
-
let endText = aeIdx + this.bFlagLen_ < pStr.length ? pStr.substr(aeIdx + this.bFlagLen_) : null;
|
|
940
|
-
// Check it to make sure it's valid, and if not, throw an error
|
|
885
|
+
let endText = aeIdx + this.bFlagLen_ < pStr.length ? pStr.substr(aeIdx + this.bFlagLen_) : null;
|
|
941
886
|
|
|
887
|
+
// Get the index of the annotation in this.annotations_.
|
|
888
|
+
// Check it to make sure it's valid, and if not, throw an error
|
|
942
889
|
let idx = pStr.substring(this.bFlagLen_, aeIdx);
|
|
943
890
|
let idxNum = Number(idx);
|
|
944
|
-
|
|
945
891
|
if (!intUtils_.isNumericString(idx) || idxNum >= this.annotations_.length) {
|
|
946
892
|
throw new Error(`Processing Error - invalid annotation index ${idx} found ` + `in ${pStr} that was created from ${origString}`);
|
|
947
|
-
}
|
|
948
|
-
|
|
893
|
+
}
|
|
949
894
|
|
|
895
|
+
// Replace the flags and annotation index with the annotation expression
|
|
950
896
|
pStr = this.annotations_[idxNum];
|
|
951
897
|
return [pStr, startText, endText];
|
|
952
898
|
} // end _getAnnoText
|
|
@@ -976,29 +922,23 @@ class UnitString {
|
|
|
976
922
|
* Each array will contain the unit code, the unit name and the
|
|
977
923
|
* unit guidance (if any).
|
|
978
924
|
*/
|
|
979
|
-
|
|
980
|
-
|
|
981
925
|
_getSuggestions(pStr) {
|
|
982
926
|
let retObj = intUtils_.getSynonyms(pStr);
|
|
983
|
-
|
|
984
927
|
if (retObj['status'] === 'succeeded') {
|
|
985
928
|
let suggSet = {};
|
|
986
929
|
suggSet['msg'] = `${pStr} is not a valid UCUM code. We found possible ` + `units that might be what was meant:`;
|
|
987
930
|
suggSet['invalidUnit'] = pStr;
|
|
988
931
|
let synLen = retObj['units'].length;
|
|
989
932
|
suggSet['units'] = [];
|
|
990
|
-
|
|
991
933
|
for (let s = 0; s < synLen; s++) {
|
|
992
934
|
let unit = retObj['units'][s];
|
|
993
935
|
let unitArray = [unit['code'], unit['name'], unit['guidance']];
|
|
994
936
|
suggSet['units'].push(unitArray);
|
|
995
937
|
}
|
|
996
|
-
|
|
997
938
|
this.suggestions_.push(suggSet);
|
|
998
939
|
} else {
|
|
999
940
|
this.retMsg_.push(`${pStr} is not a valid UCUM code. No alternatives ` + `were found.`);
|
|
1000
941
|
}
|
|
1001
|
-
|
|
1002
942
|
return retObj['status'];
|
|
1003
943
|
} // end getSuggestions
|
|
1004
944
|
|
|
@@ -1023,255 +963,245 @@ class UnitString {
|
|
|
1023
963
|
* the this.suggestions_ array will be populated if no unit (with or without
|
|
1024
964
|
* substitutions) could be found and suggestions were requested
|
|
1025
965
|
*/
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
966
|
_makeUnit(uCode, origString) {
|
|
1029
967
|
// First try the code just as is, without looking for annotations,
|
|
1030
968
|
// prefixes, exponents, or elephants.
|
|
1031
969
|
let retUnit = this.utabs_.getUnitByCode(uCode);
|
|
1032
|
-
|
|
1033
970
|
if (retUnit) {
|
|
1034
971
|
retUnit = retUnit.clone();
|
|
1035
|
-
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// If we found it, we're done. No need to parse for those elephants (or
|
|
1036
975
|
// other stuff).
|
|
1037
976
|
else if (uCode.indexOf(this.braceFlag_) >= 0) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
977
|
+
let getAnnoRet = this._getUnitWithAnnotation(uCode, origString);
|
|
978
|
+
retUnit = getAnnoRet[0];
|
|
979
|
+
if (retUnit) {
|
|
980
|
+
origString = getAnnoRet[1];
|
|
981
|
+
}
|
|
982
|
+
// If a unit is not found, retUnit will be returned null and
|
|
983
|
+
// the this.retMsg_ array will contain a message describing the problem.
|
|
984
|
+
// If a unit is found, of course, all is good. So ... nothing left
|
|
985
|
+
// to see here, move along.
|
|
986
|
+
} // end if the uCode includes an annotation
|
|
987
|
+
else {
|
|
988
|
+
// So we didn't find a unit for the full uCode or for one with
|
|
989
|
+
// annotations. Try looking for a unit that uses a carat (^)
|
|
990
|
+
// instead of an asterisk (*)
|
|
1041
991
|
|
|
992
|
+
if (uCode.indexOf('^') > -1) {
|
|
993
|
+
let tryCode = uCode.replace('^', '*');
|
|
994
|
+
retUnit = this.utabs_.getUnitByCode(tryCode);
|
|
1042
995
|
if (retUnit) {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
retUnit = retUnit.clone();
|
|
1060
|
-
retUnit.csCode_ = retUnit.csCode_.replace('*', '^');
|
|
1061
|
-
retUnit.ciCode_ = retUnit.ciCode_.replace('*', '^');
|
|
1062
|
-
}
|
|
1063
|
-
} // If that didn't work, check to see if it should have brackets
|
|
1064
|
-
// around it (uCode = degF when it should be [degF]
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
if (!retUnit) {
|
|
1068
|
-
let addBrackets = '[' + uCode + ']';
|
|
1069
|
-
retUnit = this.utabs_.getUnitByCode(addBrackets);
|
|
1070
|
-
|
|
1071
|
-
if (retUnit) {
|
|
1072
|
-
retUnit = retUnit.clone();
|
|
1073
|
-
origString = origString.replace(uCode, addBrackets);
|
|
1074
|
-
this.retMsg_.push(`${uCode} is not a valid unit expression, but ` + `${addBrackets} is.\n` + this.vcMsgStart_ + `${addBrackets} (${retUnit.name_})${this.vcMsgEnd_}`);
|
|
1075
|
-
} // end if we found the unit after adding brackets
|
|
1076
|
-
|
|
1077
|
-
} // end trying to add brackets
|
|
1078
|
-
// If we didn't find it, try it as a name
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (!retUnit) {
|
|
1082
|
-
let retUnitAry = this.utabs_.getUnitByName(uCode);
|
|
1083
|
-
|
|
1084
|
-
if (retUnitAry && retUnitAry.length > 0) {
|
|
1085
|
-
retUnit = retUnitAry[0].clone();
|
|
1086
|
-
let mString = 'The UCUM code for ' + uCode + ' is ' + retUnit.csCode_ + '.\n' + this.vcMsgStart_ + retUnit.csCode_ + this.vcMsgEnd_;
|
|
1087
|
-
let dupMsg = false;
|
|
1088
|
-
|
|
1089
|
-
for (let r = 0; r < this.retMsg_.length && !dupMsg; r++) dupMsg = this.retMsg_[r] === mString;
|
|
1090
|
-
|
|
1091
|
-
if (!dupMsg) this.retMsg_.push(mString);
|
|
1092
|
-
let rStr = new RegExp('(^|[.\/({])(' + uCode + ')($|[.\/)}])');
|
|
1093
|
-
let res = origString.match(rStr);
|
|
1094
|
-
origString = origString.replace(rStr, res[1] + retUnit.csCode_ + res[3]);
|
|
1095
|
-
uCode = retUnit.csCode_;
|
|
1096
|
-
}
|
|
1097
|
-
} // If we still don't have a unit, try assuming a modifier (prefix and/or
|
|
1098
|
-
// exponent) and look for a unit without the modifier
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
if (!retUnit) {
|
|
1102
|
-
// Well, first see if it's one of the special units. If so,
|
|
1103
|
-
// replace the placeholder text with the actual unit string, keeping
|
|
1104
|
-
// whatever text (probably a prefix) goes with the unit string.
|
|
1105
|
-
let sUnit = null;
|
|
996
|
+
retUnit = retUnit.clone();
|
|
997
|
+
retUnit.csCode_ = retUnit.csCode_.replace('*', '^');
|
|
998
|
+
retUnit.ciCode_ = retUnit.ciCode_.replace('*', '^');
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
// If that didn't work, check to see if it should have brackets
|
|
1002
|
+
// around it (uCode = degF when it should be [degF]
|
|
1003
|
+
if (!retUnit) {
|
|
1004
|
+
let addBrackets = '[' + uCode + ']';
|
|
1005
|
+
retUnit = this.utabs_.getUnitByCode(addBrackets);
|
|
1006
|
+
if (retUnit) {
|
|
1007
|
+
retUnit = retUnit.clone();
|
|
1008
|
+
origString = origString.replace(uCode, addBrackets);
|
|
1009
|
+
this.retMsg_.push(`${uCode} is not a valid unit expression, but ` + `${addBrackets} is.\n` + this.vcMsgStart_ + `${addBrackets} (${retUnit.name_})${this.vcMsgEnd_}`);
|
|
1010
|
+
} // end if we found the unit after adding brackets
|
|
1011
|
+
} // end trying to add brackets
|
|
1106
1012
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1013
|
+
// If we didn't find it, try it as a name
|
|
1014
|
+
if (!retUnit) {
|
|
1015
|
+
let retUnitAry = this.utabs_.getUnitByName(uCode);
|
|
1016
|
+
if (retUnitAry && retUnitAry.length > 0) {
|
|
1017
|
+
retUnit = retUnitAry[0].clone();
|
|
1018
|
+
let mString = 'The UCUM code for ' + uCode + ' is ' + retUnit.csCode_ + '.\n' + this.vcMsgStart_ + retUnit.csCode_ + this.vcMsgEnd_;
|
|
1019
|
+
let dupMsg = false;
|
|
1020
|
+
for (let r = 0; r < this.retMsg_.length && !dupMsg; r++) dupMsg = this.retMsg_[r] === mString;
|
|
1021
|
+
if (!dupMsg) this.retMsg_.push(mString);
|
|
1022
|
+
let rStr = new RegExp('(^|[.\/({])(' + uCode + ')($|[.\/)}])');
|
|
1023
|
+
let res = origString.match(rStr);
|
|
1024
|
+
origString = origString.replace(rStr, res[1] + retUnit.csCode_ + res[3]);
|
|
1025
|
+
uCode = retUnit.csCode_;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1110
1028
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1029
|
+
// If we still don't have a unit, try assuming a modifier (prefix and/or
|
|
1030
|
+
// exponent) and look for a unit without the modifier
|
|
1031
|
+
if (!retUnit) {
|
|
1032
|
+
// Well, first see if it's one of the special units. If so,
|
|
1033
|
+
// replace the placeholder text with the actual unit string, keeping
|
|
1034
|
+
// whatever text (probably a prefix) goes with the unit string.
|
|
1035
|
+
let sUnit = null;
|
|
1036
|
+
for (sUnit in Ucum.specUnits_) {
|
|
1037
|
+
if (uCode.indexOf(Ucum.specUnits_[sUnit]) !== -1) uCode = uCode.replace(Ucum.specUnits_[sUnit], sUnit);
|
|
1038
|
+
}
|
|
1039
|
+
retUnit = this.utabs_.getUnitByCode(uCode);
|
|
1040
|
+
if (retUnit) retUnit = retUnit.clone();
|
|
1041
|
+
}
|
|
1042
|
+
if (!retUnit) {
|
|
1043
|
+
let origCode = uCode;
|
|
1044
|
+
let origUnit = null;
|
|
1045
|
+
let exp = null;
|
|
1046
|
+
let pfxCode = null;
|
|
1047
|
+
let pfxObj = null;
|
|
1048
|
+
let pfxVal = null;
|
|
1049
|
+
let pfxExp = null;
|
|
1050
|
+
|
|
1051
|
+
// Look first for an exponent. If we got one, separate it out and
|
|
1052
|
+
// try to get the unit again
|
|
1053
|
+
let codeAndExp = this._isCodeWithExponent(uCode);
|
|
1054
|
+
if (codeAndExp) {
|
|
1055
|
+
uCode = codeAndExp[0];
|
|
1056
|
+
exp = codeAndExp[1];
|
|
1057
|
+
origUnit = this.utabs_.getUnitByCode(uCode);
|
|
1058
|
+
}
|
|
1114
1059
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1060
|
+
// If an exponent is found but it's not a valid number, e.g. "2-1",
|
|
1061
|
+
// mark the unit invalid. Otherwise, the "-1" part will be ignored
|
|
1062
|
+
// because parseInt("2-1") results in 2. See LF-2870.
|
|
1063
|
+
if (exp && isNaN(exp)) {
|
|
1064
|
+
retUnit = null;
|
|
1065
|
+
this.retMsg_.push(`${origCode} is not a valid UCUM code.`);
|
|
1066
|
+
} else {
|
|
1067
|
+
// If we still don't have a unit, separate out the prefix, if any,
|
|
1068
|
+
// and try without it.
|
|
1069
|
+
if (!origUnit) {
|
|
1070
|
+
// Try for a single character prefix first.
|
|
1071
|
+
pfxCode = uCode.charAt(0);
|
|
1072
|
+
pfxObj = this.pfxTabs_.getPrefixByCode(pfxCode);
|
|
1073
|
+
|
|
1074
|
+
// if we got a prefix, get its info and remove it from the unit code
|
|
1075
|
+
if (pfxObj) {
|
|
1076
|
+
pfxVal = pfxObj.getValue();
|
|
1077
|
+
pfxExp = pfxObj.getExp();
|
|
1078
|
+
let pCodeLen = pfxCode.length;
|
|
1079
|
+
uCode = uCode.substr(pCodeLen);
|
|
1080
|
+
|
|
1081
|
+
// try again for the unit
|
|
1130
1082
|
origUnit = this.utabs_.getUnitByCode(uCode);
|
|
1131
|
-
} // If we still don't have a unit, separate out the prefix, if any,
|
|
1132
|
-
// and try without it.
|
|
1133
|
-
|
|
1134
1083
|
|
|
1135
|
-
|
|
1136
|
-
//
|
|
1137
|
-
|
|
1138
|
-
|
|
1084
|
+
// If we still don't have a unit, see if the prefix could be the
|
|
1085
|
+
// two character "da" (deka) prefix. That's the only prefix with
|
|
1086
|
+
// two characters, and without this check it's interpreted as "d"
|
|
1087
|
+
// (deci) and the "a" is considered part of the unit code.
|
|
1139
1088
|
|
|
1140
|
-
if (
|
|
1089
|
+
if (!origUnit && pfxCode == 'd' && uCode.substr(0, 1) == 'a') {
|
|
1090
|
+
pfxCode = 'da';
|
|
1091
|
+
pfxObj = this.pfxTabs_.getPrefixByCode(pfxCode);
|
|
1141
1092
|
pfxVal = pfxObj.getValue();
|
|
1142
|
-
|
|
1143
|
-
let pCodeLen = pfxCode.length;
|
|
1144
|
-
uCode = uCode.substr(pCodeLen); // try again for the unit
|
|
1145
|
-
|
|
1146
|
-
origUnit = this.utabs_.getUnitByCode(uCode); // If we still don't have a unit, see if the prefix could be the
|
|
1147
|
-
// two character "da" (deka) prefix. That's the only prefix with
|
|
1148
|
-
// two characters, and without this check it's interpreted as "d"
|
|
1149
|
-
// (deci) and the "a" is considered part of the unit code.
|
|
1150
|
-
|
|
1151
|
-
if (!origUnit && pfxCode == 'd' && uCode.substr(0, 1) == 'a') {
|
|
1152
|
-
pfxCode = 'da';
|
|
1153
|
-
pfxObj = this.pfxTabs_.getPrefixByCode(pfxCode);
|
|
1154
|
-
pfxVal = pfxObj.getValue();
|
|
1155
|
-
uCode = uCode.substr(1); // try one more time for the unit
|
|
1156
|
-
|
|
1157
|
-
origUnit = this.utabs_.getUnitByCode(uCode);
|
|
1158
|
-
} // Reject the unit we found if it might have another prefix.
|
|
1159
|
-
// Such things are in our tables through the LOINC source_
|
|
1160
|
-
// (ucum.csv) which has guidance and synonyms. I think it should be
|
|
1161
|
-
// safe to exclude anything whose source is LOINC from having a
|
|
1162
|
-
// prefix.
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
if (origUnit && origUnit.source_ == 'LOINC') origUnit = null;
|
|
1166
|
-
} // end if we found a prefix
|
|
1167
|
-
|
|
1168
|
-
} // end if we didn't get a unit after removing an exponent
|
|
1169
|
-
// If we still haven't found anything, we're done looking.
|
|
1170
|
-
// (We tried with the full unit string, with the unit string
|
|
1171
|
-
// without the exponent, the unit string without a prefix,
|
|
1172
|
-
// common errors, etc. That's all we can try).
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
if (!origUnit) {
|
|
1176
|
-
retUnit = null; // BUT if the user asked for suggestions, at least look for them
|
|
1093
|
+
uCode = uCode.substr(1);
|
|
1177
1094
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
} else {
|
|
1181
|
-
this.retMsg_.push(`${origCode} is not a valid UCUM code.`);
|
|
1095
|
+
// try one more time for the unit
|
|
1096
|
+
origUnit = this.utabs_.getUnitByCode(uCode);
|
|
1182
1097
|
}
|
|
1183
|
-
} else {
|
|
1184
|
-
// Otherwise we found a unit object. Clone it and then apply the
|
|
1185
|
-
// prefix and exponent, if any, to it. And remove the guidance.
|
|
1186
|
-
retUnit = origUnit.clone(); // If we are here, this is only part of the full unit string, so it is
|
|
1187
|
-
// not a base unit, and the synonyms will mostly likely not be correct for the full
|
|
1188
|
-
// string.
|
|
1189
|
-
|
|
1190
|
-
retUnit.resetFieldsForDerivedUnit();
|
|
1191
|
-
let theDim = retUnit.getProperty('dim_');
|
|
1192
|
-
let theMag = retUnit.getProperty('magnitude_');
|
|
1193
|
-
let theName = retUnit.getProperty('name_');
|
|
1194
|
-
let theCiCode = retUnit.getProperty('ciCode_');
|
|
1195
|
-
let thePrintSymbol = retUnit.getProperty('printSymbol_'); // If there is an exponent for the unit, apply it to the dimension
|
|
1196
|
-
// and magnitude now
|
|
1197
|
-
|
|
1198
|
-
if (exp) {
|
|
1199
|
-
exp = parseInt(exp);
|
|
1200
|
-
let expMul = exp;
|
|
1201
|
-
if (theDim) theDim = theDim.mul(exp);
|
|
1202
|
-
theMag = Math.pow(theMag, exp);
|
|
1203
|
-
retUnit.assignVals({
|
|
1204
|
-
'magnitude_': theMag
|
|
1205
|
-
}); // If there is also a prefix, apply the exponent to the prefix.
|
|
1206
|
-
|
|
1207
|
-
if (pfxObj) {
|
|
1208
|
-
// if the prefix base is 10 it will have an exponent. Multiply
|
|
1209
|
-
// the current prefix exponent by the exponent for the unit
|
|
1210
|
-
// we're working with. Then raise the prefix value to the level
|
|
1211
|
-
// defined by the exponent.
|
|
1212
|
-
if (pfxExp) {
|
|
1213
|
-
expMul *= pfxObj.getExp();
|
|
1214
|
-
pfxVal = Math.pow(10, expMul);
|
|
1215
|
-
} // If the prefix base is not 10, it won't have an exponent.
|
|
1216
|
-
// At the moment I don't see any units using the prefixes
|
|
1217
|
-
// that aren't base 10. But if we get one the prefix value
|
|
1218
|
-
// will be applied to the magnitude (below) if the unit does
|
|
1219
|
-
// not have a conversion function, and to the conversion prefix
|
|
1220
|
-
// if it does.
|
|
1221
|
-
|
|
1222
|
-
} // end if there's a prefix as well as the exponent
|
|
1223
|
-
|
|
1224
|
-
} // end if there's an exponent
|
|
1225
|
-
// Now apply the prefix, if there is one, to the conversion
|
|
1226
|
-
// prefix or the magnitude
|
|
1227
1098
|
|
|
1099
|
+
// Reject the unit we found if it might have another prefix.
|
|
1100
|
+
// Such things are in our tables through the LOINC source_
|
|
1101
|
+
// (ucum.csv) which has guidance and synonyms. I think it should be
|
|
1102
|
+
// safe to exclude anything whose source is LOINC from having a
|
|
1103
|
+
// prefix.
|
|
1104
|
+
if (origUnit && origUnit.source_ == 'LOINC') origUnit = null;
|
|
1105
|
+
} // end if we found a prefix
|
|
1106
|
+
} // end if we didn't get a unit after removing an exponent
|
|
1107
|
+
|
|
1108
|
+
// If we still haven't found anything, we're done looking.
|
|
1109
|
+
// (We tried with the full unit string, with the unit string
|
|
1110
|
+
// without the exponent, the unit string without a prefix,
|
|
1111
|
+
// common errors, etc. That's all we can try).
|
|
1112
|
+
if (!origUnit) {
|
|
1113
|
+
retUnit = null;
|
|
1114
|
+
// BUT if the user asked for suggestions, at least look for them
|
|
1115
|
+
if (this.suggestions_) {
|
|
1116
|
+
let suggestStat = this._getSuggestions(origCode);
|
|
1117
|
+
} else {
|
|
1118
|
+
this.retMsg_.push(`${origCode} is not a valid UCUM code.`);
|
|
1119
|
+
}
|
|
1120
|
+
} else {
|
|
1121
|
+
// Otherwise we found a unit object. Clone it and then apply the
|
|
1122
|
+
// prefix and exponent, if any, to it. And remove the guidance.
|
|
1123
|
+
retUnit = origUnit.clone();
|
|
1124
|
+
// If we are here, this is only part of the full unit string, so it is
|
|
1125
|
+
// not a base unit, and the synonyms will mostly likely not be correct for the full
|
|
1126
|
+
// string.
|
|
1127
|
+
retUnit.resetFieldsForDerivedUnit();
|
|
1128
|
+
let theDim = retUnit.getProperty('dim_');
|
|
1129
|
+
let theMag = retUnit.getProperty('magnitude_');
|
|
1130
|
+
let theName = retUnit.getProperty('name_');
|
|
1131
|
+
let theCiCode = retUnit.getProperty('ciCode_');
|
|
1132
|
+
let thePrintSymbol = retUnit.getProperty('printSymbol_');
|
|
1133
|
+
// If there is an exponent for the unit, apply it to the dimension
|
|
1134
|
+
// and magnitude now
|
|
1135
|
+
if (exp) {
|
|
1136
|
+
exp = parseInt(exp);
|
|
1137
|
+
let expMul = exp;
|
|
1138
|
+
if (theDim) theDim = theDim.mul(exp);
|
|
1139
|
+
theMag = Math.pow(theMag, exp);
|
|
1140
|
+
retUnit.assignVals({
|
|
1141
|
+
'magnitude_': theMag
|
|
1142
|
+
});
|
|
1228
1143
|
|
|
1144
|
+
// If there is also a prefix, apply the exponent to the prefix.
|
|
1229
1145
|
if (pfxObj) {
|
|
1230
|
-
if
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
'magnitude_': theMag
|
|
1238
|
-
});
|
|
1146
|
+
// if the prefix base is 10 it will have an exponent. Multiply
|
|
1147
|
+
// the current prefix exponent by the exponent for the unit
|
|
1148
|
+
// we're working with. Then raise the prefix value to the level
|
|
1149
|
+
// defined by the exponent.
|
|
1150
|
+
if (pfxExp) {
|
|
1151
|
+
expMul *= pfxObj.getExp();
|
|
1152
|
+
pfxVal = Math.pow(10, expMul);
|
|
1239
1153
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
if
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1154
|
+
// If the prefix base is not 10, it won't have an exponent.
|
|
1155
|
+
// At the moment I don't see any units using the prefixes
|
|
1156
|
+
// that aren't base 10. But if we get one the prefix value
|
|
1157
|
+
// will be applied to the magnitude (below) if the unit does
|
|
1158
|
+
// not have a conversion function, and to the conversion prefix
|
|
1159
|
+
// if it does.
|
|
1160
|
+
} // end if there's a prefix as well as the exponent
|
|
1161
|
+
} // end if there's an exponent
|
|
1162
|
+
|
|
1163
|
+
// Now apply the prefix, if there is one, to the conversion
|
|
1164
|
+
// prefix or the magnitude
|
|
1165
|
+
if (pfxObj) {
|
|
1166
|
+
if (retUnit.cnv_) {
|
|
1251
1167
|
retUnit.assignVals({
|
|
1252
|
-
'
|
|
1253
|
-
'csCode_': theCode,
|
|
1254
|
-
'ciCode_': theCiCode,
|
|
1255
|
-
'printSymbol_': thePrintSymbol
|
|
1168
|
+
'cnvPfx_': pfxVal
|
|
1256
1169
|
});
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
if (exp) {
|
|
1260
|
-
let expStr = exp.toString();
|
|
1170
|
+
} else {
|
|
1171
|
+
theMag *= pfxVal;
|
|
1261
1172
|
retUnit.assignVals({
|
|
1262
|
-
'
|
|
1263
|
-
'csCode_': theCode + expStr,
|
|
1264
|
-
'ciCode_': theCiCode + expStr,
|
|
1265
|
-
'printSymbol_': thePrintSymbol + '<sup>' + expStr + '</sup>'
|
|
1173
|
+
'magnitude_': theMag
|
|
1266
1174
|
});
|
|
1267
1175
|
}
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1176
|
+
}
|
|
1177
|
+
// if we have a prefix and/or an exponent, add them to the unit
|
|
1178
|
+
// attributes - name, csCode, ciCode and print symbol
|
|
1179
|
+
let theCode = retUnit.csCode_;
|
|
1180
|
+
if (pfxObj) {
|
|
1181
|
+
theName = pfxObj.getName() + theName;
|
|
1182
|
+
theCode = pfxCode + theCode;
|
|
1183
|
+
theCiCode = pfxObj.getCiCode() + theCiCode;
|
|
1184
|
+
thePrintSymbol = pfxObj.getPrintSymbol() + thePrintSymbol;
|
|
1185
|
+
retUnit.assignVals({
|
|
1186
|
+
'name_': theName,
|
|
1187
|
+
'csCode_': theCode,
|
|
1188
|
+
'ciCode_': theCiCode,
|
|
1189
|
+
'printSymbol_': thePrintSymbol
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
if (exp) {
|
|
1193
|
+
let expStr = exp.toString();
|
|
1194
|
+
retUnit.assignVals({
|
|
1195
|
+
'name_': theName + '<sup>' + expStr + '</sup>',
|
|
1196
|
+
'csCode_': theCode + expStr,
|
|
1197
|
+
'ciCode_': theCiCode + expStr,
|
|
1198
|
+
'printSymbol_': thePrintSymbol + '<sup>' + expStr + '</sup>'
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
} // end if an original unit was found (without prefix and/or exponent)
|
|
1202
|
+
} // end if an invalid exponent wasn't found
|
|
1203
|
+
} // end if we didn't get a unit for the full unit code (w/out modifiers)
|
|
1204
|
+
} // end if we didn't find the unit on the first try, before parsing
|
|
1275
1205
|
return [retUnit, origString];
|
|
1276
1206
|
} // end _makeUnit
|
|
1277
1207
|
|
|
@@ -1288,33 +1218,32 @@ class UnitString {
|
|
|
1288
1218
|
* the this.retMsg_ array will be updated with any user messages
|
|
1289
1219
|
* (informational, error or warning) generated by this or called methods
|
|
1290
1220
|
*/
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
1221
|
_getUnitWithAnnotation(uCode, origString) {
|
|
1294
|
-
let retUnit = null;
|
|
1222
|
+
let retUnit = null;
|
|
1295
1223
|
|
|
1224
|
+
// Get the annotation and anything that precedes or follows it.
|
|
1296
1225
|
let annoRet = this._getAnnoText(uCode, origString);
|
|
1297
|
-
|
|
1298
1226
|
let annoText = annoRet[0];
|
|
1299
1227
|
let befAnnoText = annoRet[1];
|
|
1300
|
-
let aftAnnoText = annoRet[2];
|
|
1228
|
+
let aftAnnoText = annoRet[2];
|
|
1229
|
+
|
|
1230
|
+
// Add the warning about annotations - just once.
|
|
1301
1231
|
|
|
1302
|
-
if (this.bracesMsg_ && this.retMsg_.indexOf(this.bracesMsg_) === -1) this.retMsg_.push(this.bracesMsg_);
|
|
1232
|
+
if (this.bracesMsg_ && this.retMsg_.indexOf(this.bracesMsg_) === -1) this.retMsg_.push(this.bracesMsg_);
|
|
1233
|
+
|
|
1234
|
+
// If there's no text before or after the annotation, it's probably
|
|
1303
1235
|
// something that should be interpreted as a 1, e.g., {KCT'U}.
|
|
1304
1236
|
// HOWEVER, it could also be a case where someone used braces instead
|
|
1305
1237
|
// of brackets, e.g., {degF} instead of [degF]. Check for that before
|
|
1306
1238
|
// we assume it should be a 1.
|
|
1307
|
-
|
|
1308
1239
|
let msgLen = this.retMsg_.length;
|
|
1309
|
-
|
|
1310
1240
|
if (!befAnnoText && !aftAnnoText) {
|
|
1311
1241
|
let tryBrackets = '[' + annoText.substring(1, annoText.length - 1) + ']';
|
|
1242
|
+
let mkUnitRet = this._makeUnit(tryBrackets, origString);
|
|
1312
1243
|
|
|
1313
|
-
|
|
1244
|
+
// Nearly anything inside braces is valid, so we don't want to change the
|
|
1314
1245
|
// unit, but we can put the found unit in the message as a sort of
|
|
1315
1246
|
// warning.
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
1247
|
if (mkUnitRet[0]) {
|
|
1319
1248
|
retUnit = uCode;
|
|
1320
1249
|
this.retMsg_.push(`${annoText} is a valid unit expression, but ` + `did you mean ${tryBrackets} (${mkUnitRet[0].name_})?`);
|
|
@@ -1323,11 +1252,11 @@ class UnitString {
|
|
|
1323
1252
|
if (this.retMsg_.length > msgLen) {
|
|
1324
1253
|
this.retMsg_.pop();
|
|
1325
1254
|
}
|
|
1326
|
-
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// This is the case where the string is only this annotation.
|
|
1327
1258
|
// Create and return a unit object, as we do for numeric units in
|
|
1328
1259
|
// parseString.
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
1260
|
retUnit = new Unit({
|
|
1332
1261
|
'csCode_': annoText,
|
|
1333
1262
|
'ciCode_': annoText,
|
|
@@ -1336,59 +1265,62 @@ class UnitString {
|
|
|
1336
1265
|
});
|
|
1337
1266
|
} // end if it's only an annotation
|
|
1338
1267
|
else {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1268
|
+
// if there's text before and no text after, assume the text before
|
|
1269
|
+
// the annotation is the unit code (with an annotation following it).
|
|
1270
|
+
// Call _makeUnit for the text before the annotation.
|
|
1271
|
+
if (befAnnoText && !aftAnnoText) {
|
|
1272
|
+
// make sure that what's before the annoText is not a number, e.g.,
|
|
1273
|
+
// /100{cells}. But f it is a number, just set the return unit to
|
|
1274
|
+
// the number.
|
|
1275
|
+
if (intUtils_.isIntegerUnit(befAnnoText)) {
|
|
1276
|
+
retUnit = befAnnoText;
|
|
1277
|
+
}
|
|
1278
|
+
// Otherwise try to find a unit
|
|
1279
|
+
else {
|
|
1280
|
+
let mkUnitRet = this._makeUnit(befAnnoText, origString);
|
|
1352
1281
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
} // else if there's only text after the annotation, try for a unit
|
|
1363
|
-
// from the after text and assume the user put the annotation in
|
|
1364
|
-
// the wrong place (and tell them)
|
|
1365
|
-
else if (!befAnnoText && aftAnnoText) {
|
|
1366
|
-
// Again, test for a number and if it is a number, set the return
|
|
1367
|
-
// unit to the number.
|
|
1368
|
-
if (intUtils_.isIntegerUnit(aftAnnoText)) {
|
|
1369
|
-
retUnit = aftAnnoText + annoText;
|
|
1370
|
-
this.retMsg_.push(`The annotation ${annoText} before the ``${aftAnnoText} is invalid.\n` + this.vcMsgStart_ + retUnit + this.vcMsgEnd_);
|
|
1371
|
-
} else {
|
|
1372
|
-
let mkUnitRet = this._makeUnit(aftAnnoText, origString);
|
|
1373
|
-
|
|
1374
|
-
if (mkUnitRet[0]) {
|
|
1375
|
-
retUnit = mkUnitRet[0];
|
|
1376
|
-
retUnit.csCode_ += annoText;
|
|
1377
|
-
origString = retUnit.csCode_;
|
|
1378
|
-
this.retMsg_.push(`The annotation ${annoText} before the unit ` + `code is invalid.\n` + this.vcMsgStart_ + retUnit.csCode_ + this.vcMsgEnd_);
|
|
1379
|
-
} // Otherwise add a not found message
|
|
1380
|
-
else {
|
|
1381
|
-
this.retMsg_.push(`Unable to find a unit for ${befAnnoText} that ` + `follows the annotation ${annoText}.`);
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
} // else it's got text before AND after the annotation. Now what?
|
|
1385
|
-
// For now this is an error. This may be a case of a missing
|
|
1386
|
-
// operator but that is not handled yet.
|
|
1282
|
+
// if a unit was returned
|
|
1283
|
+
if (mkUnitRet[0]) {
|
|
1284
|
+
retUnit = mkUnitRet[0];
|
|
1285
|
+
retUnit.csCode_ += annoText;
|
|
1286
|
+
origString = mkUnitRet[1];
|
|
1287
|
+
}
|
|
1288
|
+
// Otherwise add a not found message
|
|
1387
1289
|
else {
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1290
|
+
this.retMsg_.push(`Unable to find a unit for ${befAnnoText} that ` + `precedes the annotation ${annoText}.`);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
// else if there's only text after the annotation, try for a unit
|
|
1295
|
+
// from the after text and assume the user put the annotation in
|
|
1296
|
+
// the wrong place (and tell them)
|
|
1297
|
+
else if (!befAnnoText && aftAnnoText) {
|
|
1298
|
+
// Again, test for a number and if it is a number, set the return
|
|
1299
|
+
// unit to the number.
|
|
1300
|
+
if (intUtils_.isIntegerUnit(aftAnnoText)) {
|
|
1301
|
+
retUnit = aftAnnoText + annoText;
|
|
1302
|
+
this.retMsg_.push(`The annotation ${annoText} before the ``${aftAnnoText} is invalid.\n` + this.vcMsgStart_ + retUnit + this.vcMsgEnd_);
|
|
1303
|
+
} else {
|
|
1304
|
+
let mkUnitRet = this._makeUnit(aftAnnoText, origString);
|
|
1305
|
+
if (mkUnitRet[0]) {
|
|
1306
|
+
retUnit = mkUnitRet[0];
|
|
1307
|
+
retUnit.csCode_ += annoText;
|
|
1308
|
+
origString = retUnit.csCode_;
|
|
1309
|
+
this.retMsg_.push(`The annotation ${annoText} before the unit ` + `code is invalid.\n` + this.vcMsgStart_ + retUnit.csCode_ + this.vcMsgEnd_);
|
|
1310
|
+
}
|
|
1311
|
+
// Otherwise add a not found message
|
|
1312
|
+
else {
|
|
1313
|
+
this.retMsg_.push(`Unable to find a unit for ${befAnnoText} that ` + `follows the annotation ${annoText}.`);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
// else it's got text before AND after the annotation. Now what?
|
|
1318
|
+
// For now this is an error. This may be a case of a missing
|
|
1319
|
+
// operator but that is not handled yet.
|
|
1320
|
+
else {
|
|
1321
|
+
this.retMsg_.push(`Unable to find a unit for ${befAnnoText}${annoText}` + `${aftAnnoText}.\nWe are not sure how to interpret text both before ` + `and after the annotation. Sorry`);
|
|
1322
|
+
}
|
|
1323
|
+
} // else if there's text before/and or after the annotation
|
|
1392
1324
|
|
|
1393
1325
|
return [retUnit, origString];
|
|
1394
1326
|
} // end _getUnitWithAnnotations
|
|
@@ -1409,11 +1341,8 @@ class UnitString {
|
|
|
1409
1341
|
* the this.retMsg_ array will be updated with any user messages
|
|
1410
1342
|
* (informational, error or warning) generated by this or called methods
|
|
1411
1343
|
*/
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
1344
|
_performUnitArithmetic(uArray, origString) {
|
|
1415
1345
|
let finalUnit = uArray[0]['un'];
|
|
1416
|
-
|
|
1417
1346
|
if (intUtils_.isIntegerUnit(finalUnit)) {
|
|
1418
1347
|
finalUnit = new Unit({
|
|
1419
1348
|
'csCode_': finalUnit,
|
|
@@ -1422,14 +1351,12 @@ class UnitString {
|
|
|
1422
1351
|
'name_': finalUnit
|
|
1423
1352
|
});
|
|
1424
1353
|
}
|
|
1425
|
-
|
|
1426
1354
|
let uLen = uArray.length;
|
|
1427
|
-
let endProcessing = false;
|
|
1355
|
+
let endProcessing = false;
|
|
1356
|
+
// Perform the arithmetic for the units, starting with the first 2 units.
|
|
1428
1357
|
// We only need to do the arithmetic if we have more than one unit.
|
|
1429
|
-
|
|
1430
1358
|
for (let u2 = 1; u2 < uLen && !endProcessing; u2++) {
|
|
1431
1359
|
let nextUnit = uArray[u2]['un'];
|
|
1432
|
-
|
|
1433
1360
|
if (intUtils_.isIntegerUnit(nextUnit)) {
|
|
1434
1361
|
nextUnit = new Unit({
|
|
1435
1362
|
'csCode_': nextUnit,
|
|
@@ -1438,14 +1365,11 @@ class UnitString {
|
|
|
1438
1365
|
'name_': nextUnit
|
|
1439
1366
|
});
|
|
1440
1367
|
}
|
|
1441
|
-
|
|
1442
1368
|
if (nextUnit === null || typeof nextUnit !== 'number' && !nextUnit.getProperty) {
|
|
1443
1369
|
let msgString = `Unit string (${origString}) contains unrecognized ` + 'element';
|
|
1444
|
-
|
|
1445
1370
|
if (nextUnit) {
|
|
1446
1371
|
msgString += ` (${this.openEmph_}${nextUnit.toString()}` + `${this.closeEmph_})`;
|
|
1447
1372
|
}
|
|
1448
|
-
|
|
1449
1373
|
msgString += '; could not parse full string. Sorry';
|
|
1450
1374
|
this.retMsg_.push(msgString);
|
|
1451
1375
|
endProcessing = true;
|
|
@@ -1453,9 +1377,10 @@ class UnitString {
|
|
|
1453
1377
|
try {
|
|
1454
1378
|
// Is the operation division?
|
|
1455
1379
|
let thisOp = uArray[u2]['op'];
|
|
1456
|
-
let isDiv = thisOp === '/';
|
|
1457
|
-
// are unit objects.
|
|
1380
|
+
let isDiv = thisOp === '/';
|
|
1458
1381
|
|
|
1382
|
+
// Perform the operation. Both the finalUnit and nextUnit
|
|
1383
|
+
// are unit objects.
|
|
1459
1384
|
isDiv ? finalUnit = finalUnit.divide(nextUnit) : finalUnit = finalUnit.multiplyThese(nextUnit);
|
|
1460
1385
|
} catch (err) {
|
|
1461
1386
|
this.retMsg_.unshift(err.message);
|
|
@@ -1463,10 +1388,7 @@ class UnitString {
|
|
|
1463
1388
|
finalUnit = null;
|
|
1464
1389
|
}
|
|
1465
1390
|
} // end if we have another valid unit/number to process
|
|
1466
|
-
|
|
1467
1391
|
} // end do for each unit after the first one
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
1392
|
return finalUnit;
|
|
1471
1393
|
} // end _performUnitArithmetic
|
|
1472
1394
|
|
|
@@ -1494,25 +1416,21 @@ class UnitString {
|
|
|
1494
1416
|
* if there is no trailing number or something follows the trailing
|
|
1495
1417
|
* number, or if the first part is not characters.
|
|
1496
1418
|
*/
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
1419
|
_isCodeWithExponent(uCode) {
|
|
1500
1420
|
let ret = [];
|
|
1501
|
-
let res = uCode.match(/(^[^\-\+]+?)([\-\+\d]+)$/);
|
|
1502
|
-
// unit and return both (as separate values)
|
|
1421
|
+
let res = uCode.match(/(^[^\-\+]+?)([\-\+\d]+)$/);
|
|
1503
1422
|
|
|
1423
|
+
// If we got a return with an exponent, separate the exponent from the
|
|
1424
|
+
// unit and return both (as separate values)
|
|
1504
1425
|
if (res && res[2] && res[2] !== "") {
|
|
1505
1426
|
ret.push(res[1]);
|
|
1506
1427
|
ret.push(res[2]);
|
|
1507
1428
|
} // end if we got an exponent
|
|
1508
1429
|
else {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1430
|
+
ret = null;
|
|
1431
|
+
}
|
|
1512
1432
|
return ret;
|
|
1513
1433
|
} // end _isCodeWithExponent
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
1434
|
} // end class UnitString
|
|
1517
1435
|
|
|
1518
1436
|
/**
|
|
@@ -1526,18 +1444,13 @@ class UnitString {
|
|
|
1526
1444
|
*
|
|
1527
1445
|
* @return the singleton UnitString object.
|
|
1528
1446
|
*/
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
1447
|
exports.UnitString = UnitString;
|
|
1532
|
-
|
|
1533
1448
|
_defineProperty(UnitString, "INVALID_ANNOTATION_CHAR_MSG", 'An invalid character was found in the annotation ');
|
|
1534
|
-
|
|
1535
|
-
// A regular expression for validating annotation strings.
|
|
1536
1449
|
_defineProperty(UnitString, "VALID_ANNOTATION_REGEX", /^\{[!-z|~]*\}$/);
|
|
1537
|
-
|
|
1538
1450
|
UnitString.getInstance = function () {
|
|
1539
1451
|
return new UnitString();
|
|
1540
1452
|
};
|
|
1453
|
+
|
|
1541
1454
|
/*
|
|
1542
1455
|
// Perform the first request for the object, to set the getInstance method.
|
|
1543
1456
|
UnitString.getInstance();
|