strnum 2.0.4 → 2.1.0
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/CHANGELOG.md +14 -0
- package/algo.stflow +84 -0
- package/package.json +1 -1
- package/strnum.js +55 -35
- package/strnum.test.js +10 -0
- package/test.js +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
|
|
2
|
+
**2.1.0 / 2025-05-01**
|
|
3
|
+
- fix e-notation
|
|
4
|
+
- to return string when invalid enotation is found. Eg `E24`
|
|
5
|
+
- to return valid number when only leading zero before e char is present
|
|
6
|
+
|
|
7
|
+
**2.0.5 / 2025-02-27**
|
|
8
|
+
- changes done in 1.1.2
|
|
9
|
+
|
|
10
|
+
**1.1.2 / 2025-02-27**
|
|
11
|
+
- fix skiplike for 0
|
|
12
|
+
|
|
13
|
+
**1.1.1 / 2025-02-21**
|
|
14
|
+
- All recent fixes of version 2
|
|
15
|
+
|
|
2
16
|
**2.0.4 / 2025-02-20**
|
|
3
17
|
- remove console log
|
|
4
18
|
|
package/algo.stflow
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
|
|
2
|
+
FLOW: toNumber
|
|
3
|
+
input: x, options
|
|
4
|
+
IF not string
|
|
5
|
+
END x
|
|
6
|
+
ELSE_IF should skip
|
|
7
|
+
END x
|
|
8
|
+
ELSE_IF 0
|
|
9
|
+
END 0
|
|
10
|
+
ELSE_IF hex is supported AND x is hex
|
|
11
|
+
END int of x of base 16
|
|
12
|
+
ELSE_IF possible e notation
|
|
13
|
+
FOLLOW: resolve enotation (x, trimmed x, options)
|
|
14
|
+
ELSE
|
|
15
|
+
IF match numeric pattern
|
|
16
|
+
separate sign, leading zeros, pure number
|
|
17
|
+
IF x doesn't starts with "[+-]0."
|
|
18
|
+
END number(x)
|
|
19
|
+
IF leading zeros are not allowed
|
|
20
|
+
IF leading zeros > 1
|
|
21
|
+
#00.1
|
|
22
|
+
END x
|
|
23
|
+
ELSE_IF leading zeros == 1 AND decimal is not adjacent to leading zeros
|
|
24
|
+
#06.5
|
|
25
|
+
#but not 0.65, .65, 6.0
|
|
26
|
+
END x
|
|
27
|
+
ELSE_IF str has only zeros
|
|
28
|
+
END 0
|
|
29
|
+
ELSE
|
|
30
|
+
parse x to number
|
|
31
|
+
IF parsed x == 0 or -0
|
|
32
|
+
END parsed x
|
|
33
|
+
ELSE_IF parsed x is eNotation
|
|
34
|
+
IF conversion to enotation is allowed
|
|
35
|
+
END parsed x
|
|
36
|
+
ELSE
|
|
37
|
+
END x
|
|
38
|
+
ELSE_IF floating number
|
|
39
|
+
IF parsed x is 0
|
|
40
|
+
END parsed x
|
|
41
|
+
ELSE_IF parsed x == number without leading 0s
|
|
42
|
+
#0.456. 0.79000
|
|
43
|
+
END parsed x
|
|
44
|
+
ELSE_IF parsed x is negative AND == parsed x == number without leading 0s
|
|
45
|
+
END parsed x
|
|
46
|
+
ELSE
|
|
47
|
+
END x
|
|
48
|
+
ELSE_IF leading 0s are present
|
|
49
|
+
IF parsed x == x without leading 0s
|
|
50
|
+
END parsed x
|
|
51
|
+
ELSE
|
|
52
|
+
END x
|
|
53
|
+
ELSE
|
|
54
|
+
IF parsed x == x (consider sign)
|
|
55
|
+
END parsed x
|
|
56
|
+
ELSE
|
|
57
|
+
END x
|
|
58
|
+
|
|
59
|
+
ELSE
|
|
60
|
+
END x
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
FLOW: resolve enotation
|
|
65
|
+
input: x, trimmed x, options
|
|
66
|
+
IF eNotation has not to be evaluated
|
|
67
|
+
END x
|
|
68
|
+
IF match eNotation pattern
|
|
69
|
+
extract sign, eChar, leading zeros
|
|
70
|
+
find if eChar adjacent to leading zeros
|
|
71
|
+
|
|
72
|
+
IF leading zeros > 1 AND eChar adjacent to leading zeros
|
|
73
|
+
# 00e, -00e
|
|
74
|
+
END x
|
|
75
|
+
ELSE_IF exp is `0e`, `0.e`, `-0.e`, `-0e`
|
|
76
|
+
END number(x);
|
|
77
|
+
ELSE_IF leading zeros are allowed but eChar is not adjacent to leading zeros
|
|
78
|
+
# -003e2
|
|
79
|
+
remove leading zeros
|
|
80
|
+
END number(x)
|
|
81
|
+
ELSE
|
|
82
|
+
END x
|
|
83
|
+
ELSE
|
|
84
|
+
END x
|
package/package.json
CHANGED
package/strnum.js
CHANGED
|
@@ -16,32 +16,17 @@ const consider = {
|
|
|
16
16
|
export default function toNumber(str, options = {}){
|
|
17
17
|
options = Object.assign({}, consider, options );
|
|
18
18
|
if(!str || typeof str !== "string" ) return str;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
let trimmedStr = str.trim();
|
|
22
|
-
|
|
21
|
+
|
|
23
22
|
if(options.skipLike !== undefined && options.skipLike.test(trimmedStr)) return str;
|
|
23
|
+
else if(str==="0") return 0;
|
|
24
24
|
else if (options.hex && hexRegex.test(trimmedStr)) {
|
|
25
25
|
return parse_int(trimmedStr, 16);
|
|
26
26
|
// }else if (options.oct && octRegex.test(str)) {
|
|
27
27
|
// return Number.parseInt(val, 8);
|
|
28
|
-
}else if (trimmedStr.search(
|
|
29
|
-
|
|
30
|
-
// +00.123 => [ , '+', '00', '.123', ..
|
|
31
|
-
if(notation){
|
|
32
|
-
// console.log(notation)
|
|
33
|
-
if(options.leadingZeros){ //accept with leading zeros
|
|
34
|
-
trimmedStr = (notation[1] || "") + notation[3];
|
|
35
|
-
}else{
|
|
36
|
-
if(notation[2] === "0" && notation[3][0]=== "."){ //valid number
|
|
37
|
-
}else{
|
|
38
|
-
return str;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return options.eNotation ? Number(trimmedStr) : str;
|
|
42
|
-
}else{
|
|
43
|
-
return str;
|
|
44
|
-
}
|
|
28
|
+
}else if (trimmedStr.search(/.+[eE].+/)!== -1) { //eNotation
|
|
29
|
+
return resolveEnotation(str,trimmedStr,options);
|
|
45
30
|
// }else if (options.parseBin && binRegex.test(str)) {
|
|
46
31
|
// return Number.parseInt(val, 2);
|
|
47
32
|
}else{
|
|
@@ -49,33 +34,42 @@ export default function toNumber(str, options = {}){
|
|
|
49
34
|
const match = numRegex.exec(trimmedStr);
|
|
50
35
|
// +00.123 => [ , '+', '00', '.123', ..
|
|
51
36
|
if(match){
|
|
52
|
-
const sign = match[1];
|
|
37
|
+
const sign = match[1] || "";
|
|
53
38
|
const leadingZeros = match[2];
|
|
54
39
|
let numTrimmedByZeros = trimZeros(match[3]); //complete num without leading zeros
|
|
40
|
+
const decimalAdjacentToLeadingZeros = sign ? // 0., -00., 000.
|
|
41
|
+
str[leadingZeros.length+1] === "."
|
|
42
|
+
: str[leadingZeros.length] === ".";
|
|
43
|
+
|
|
55
44
|
//trim ending zeros for floating number
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
45
|
+
if(!options.leadingZeros //leading zeros are not allowed
|
|
46
|
+
&& (leadingZeros.length > 1
|
|
47
|
+
|| (leadingZeros.length === 1 && !decimalAdjacentToLeadingZeros))){
|
|
48
|
+
// 00, 00.3, +03.24, 03, 03.24
|
|
49
|
+
return str;
|
|
50
|
+
}
|
|
61
51
|
else{//no leading zeros or leading zeros are allowed
|
|
62
52
|
const num = Number(trimmedStr);
|
|
63
|
-
const
|
|
53
|
+
const parsedStr = String(num);
|
|
64
54
|
|
|
65
|
-
if(
|
|
55
|
+
if( num === 0 || num === -0) return num;
|
|
56
|
+
if(parsedStr.search(/[eE]/) !== -1){ //given number is long and parsed to eNotation
|
|
66
57
|
if(options.eNotation) return num;
|
|
67
58
|
else return str;
|
|
68
59
|
}else if(trimmedStr.indexOf(".") !== -1){ //floating number
|
|
69
|
-
if(
|
|
70
|
-
else if(
|
|
71
|
-
else if(
|
|
60
|
+
if(parsedStr === "0") return num; //0.0
|
|
61
|
+
else if(parsedStr === numTrimmedByZeros) return num; //0.456. 0.79000
|
|
62
|
+
else if( parsedStr === `${sign}${numTrimmedByZeros}`) return num;
|
|
72
63
|
else return str;
|
|
73
64
|
}
|
|
74
65
|
|
|
66
|
+
let n = leadingZeros? numTrimmedByZeros : trimmedStr;
|
|
75
67
|
if(leadingZeros){
|
|
76
|
-
|
|
68
|
+
// -009 => -9
|
|
69
|
+
return (n === parsedStr) || (sign+n === parsedStr) ? num : str
|
|
77
70
|
}else {
|
|
78
|
-
|
|
71
|
+
// +9
|
|
72
|
+
return (n === parsedStr) || (n === sign+parsedStr) ? num : str
|
|
79
73
|
}
|
|
80
74
|
}
|
|
81
75
|
}else{ //non-numeric string
|
|
@@ -84,6 +78,32 @@ export default function toNumber(str, options = {}){
|
|
|
84
78
|
}
|
|
85
79
|
}
|
|
86
80
|
|
|
81
|
+
const eNotationRegx = /^([-+])?(0*)(\d*(\.\d*)?[eE][-\+]?\d+)$/;
|
|
82
|
+
function resolveEnotation(str,trimmedStr,options){
|
|
83
|
+
if(!options.eNotation) return str;
|
|
84
|
+
const notation = trimmedStr.match(eNotationRegx);
|
|
85
|
+
if(notation){
|
|
86
|
+
let sign = notation[1] || "";
|
|
87
|
+
const eChar = notation[3].indexOf("e") === -1 ? "E" : "e";
|
|
88
|
+
const leadingZeros = notation[2];
|
|
89
|
+
const eAdjacentToLeadingZeros = sign ? // 0E.
|
|
90
|
+
str[leadingZeros.length+1] === eChar
|
|
91
|
+
: str[leadingZeros.length] === eChar;
|
|
92
|
+
|
|
93
|
+
if(leadingZeros.length > 1 && eAdjacentToLeadingZeros) return str;
|
|
94
|
+
else if(leadingZeros.length === 1
|
|
95
|
+
&& (notation[3].startsWith(`.${eChar}`) || notation[3][0] === eChar)){
|
|
96
|
+
return Number(trimmedStr);
|
|
97
|
+
}else if(options.leadingZeros && !eAdjacentToLeadingZeros){ //accept with leading zeros
|
|
98
|
+
//remove leading 0s
|
|
99
|
+
trimmedStr = (notation[1] || "") + notation[3];
|
|
100
|
+
return Number(trimmedStr);
|
|
101
|
+
}else return str;
|
|
102
|
+
}else{
|
|
103
|
+
return str;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
87
107
|
/**
|
|
88
108
|
*
|
|
89
109
|
* @param {string} numStr without leading zeros
|
|
@@ -94,7 +114,7 @@ function trimZeros(numStr){
|
|
|
94
114
|
numStr = numStr.replace(/0+$/, ""); //remove ending zeros
|
|
95
115
|
if(numStr === ".") numStr = "0";
|
|
96
116
|
else if(numStr[0] === ".") numStr = "0"+numStr;
|
|
97
|
-
else if(numStr[numStr.length-1] === ".") numStr = numStr.
|
|
117
|
+
else if(numStr[numStr.length-1] === ".") numStr = numStr.substring(0,numStr.length-1);
|
|
98
118
|
return numStr;
|
|
99
119
|
}
|
|
100
120
|
return numStr;
|
|
@@ -106,4 +126,4 @@ function parse_int(numStr, base){
|
|
|
106
126
|
else if(Number.parseInt) return Number.parseInt(numStr, base);
|
|
107
127
|
else if(window && window.parseInt) return window.parseInt(numStr, base);
|
|
108
128
|
else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported")
|
|
109
|
-
}
|
|
129
|
+
}
|
package/strnum.test.js
CHANGED
|
@@ -7,6 +7,7 @@ describe("Should convert all the valid numeric strings to number", () => {
|
|
|
7
7
|
expect(toNumber("")).toEqual("");
|
|
8
8
|
expect(toNumber("string")).toEqual("string");
|
|
9
9
|
expect(toNumber("e89794659669cb7bb967db73a7ea6889c3891727")).toEqual("e89794659669cb7bb967db73a7ea6889c3891727");
|
|
10
|
+
|
|
10
11
|
});
|
|
11
12
|
it("should not parse number with spaces or comma", () => {
|
|
12
13
|
expect(toNumber("12,12")).toEqual("12,12");
|
|
@@ -94,6 +95,7 @@ describe("Should convert all the valid numeric strings to number", () => {
|
|
|
94
95
|
expect(toNumber("-.006")).toEqual(-0.006);
|
|
95
96
|
expect(toNumber("-6.0")).toEqual(-6);
|
|
96
97
|
expect(toNumber("-06.0")).toEqual(-6);
|
|
98
|
+
expect(toNumber("+06.0")).toEqual(6);
|
|
97
99
|
|
|
98
100
|
expect(toNumber("-0.0" , { leadingZeros : false})).toEqual(-0);
|
|
99
101
|
expect(toNumber("-00.00", { leadingZeros : false})).toEqual("-00.00");
|
|
@@ -136,9 +138,17 @@ describe("Should convert all the valid numeric strings to number", () => {
|
|
|
136
138
|
|
|
137
139
|
expect(toNumber("-1.0E2") ).toEqual(-100);
|
|
138
140
|
expect(toNumber("1.0E-2")).toEqual(0.01);
|
|
141
|
+
|
|
142
|
+
expect(toNumber("E-2")).toEqual("E-2");
|
|
143
|
+
expect(toNumber("E2")).toEqual("E2");
|
|
144
|
+
expect(toNumber("0E2")).toEqual(0);
|
|
145
|
+
expect(toNumber("-0E2")).toEqual(-0);
|
|
146
|
+
expect(toNumber("00E2")).toEqual("00E2");
|
|
147
|
+
expect(toNumber("00E2", { leadingZeros : false})).toEqual("00E2");
|
|
139
148
|
});
|
|
140
149
|
|
|
141
150
|
it("should skip matching pattern", () => {
|
|
151
|
+
expect(toNumber("0", { skipLike: /.*/ })).toEqual("0");
|
|
142
152
|
expect(toNumber("+12", { skipLike: /\+[0-9]{10}/} )).toEqual(12);
|
|
143
153
|
expect(toNumber("12+12", { skipLike: /\+[0-9]{10}/} )).toEqual("12+12");
|
|
144
154
|
expect(toNumber("12+1212121212", { skipLike: /\+[0-9]{10}/} )).toEqual("12+1212121212");
|
package/test.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import toNumber from "./strnum.js";
|
|
2
|
+
|
|
3
|
+
describe("Should convert all the valid numeric strings to number", () => {
|
|
4
|
+
it("should return undefined, null, empty string, or non-numeric as it is", () => {
|
|
5
|
+
// expect(toNumber("+ 90")).toEqual("+ 90");
|
|
6
|
+
// expect(toNumber("- 90")).toEqual("- 90");
|
|
7
|
+
expect(toNumber("-10E2")).toEqual(100);
|
|
8
|
+
});
|
|
9
|
+
});
|