bep40 commited on
Commit
e0bda2a
·
verified ·
1 Parent(s): d7a6833

Upload src/viNumberFix.js

Browse files
Files changed (1) hide show
  1. src/viNumberFix.js +94 -49
src/viNumberFix.js CHANGED
@@ -29,37 +29,63 @@ var DIGIT = { "khong": 0, "mot": 1, "hai": 2, "ba": 3, "bon": 4, "nam": 5, "sau"
29
  // Scale words → multiplier
30
  var SCALE = { "muoi": 10, "tram": 100, "nghin": 1000, "ngan": 1000, "trieu": 1000000, "ty": 1000000000 };
31
 
32
- function parseNumberTokens(tokens) {
 
 
 
 
 
 
 
 
 
 
 
 
33
  var result = 0;
34
  var i = 0;
35
 
36
  while (i < tokens.length) {
37
  var base = toBaseForm(tokens[i]);
38
- var next = i + 1 < tokens.length ? toBaseForm(tokens[i + 1]) : "";
39
- var nextNext = i + 2 < tokens.length ? toBaseForm(tokens[i + 2]) : "";
40
 
41
- // Handle large scales first (ty, trieu, nghin) from right to left
42
- if (SCALE[base] !== undefined && SCALE[base] >= 1000) {
43
- if (i === 0 || SCALE[toBaseForm(tokens[i-1])] === undefined) {
44
- result += SCALE[base]; // Just "hai trieu" = 2000000
 
 
45
  i++;
 
46
  continue;
47
  }
48
- // "hai trieu lam" means 2,000,000 + 5,000 = 2,005,000
49
- if (DIGIT[base] !== undefined) {
50
- var group = DIGIT[base] * SCALE[next];
51
- result += group;
52
- i += 2;
53
- continue;
54
- }
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
 
57
  // "muoi mot" = 11
58
  if (base === "muoi" && (next === "mot" || next === "mơ")) {
59
- return 11;
60
  }
61
 
62
- // "X muoi Y" = X0 + Y (21-99)
63
  if (next === "muoi" && DIGIT[base] !== undefined) {
64
  var val = DIGIT[base] * 10;
65
  i += 2;
@@ -68,20 +94,10 @@ function parseNumberTokens(tokens) {
68
  if (ones === "mot" || ones === "mơ") val += 1;
69
  else if (DIGIT[ones] !== undefined) val += DIGIT[ones];
70
  }
71
- return val;
72
- }
73
-
74
- // "X muoi" standalone = X0
75
- if (next === "muoi" && DIGIT[base] !== undefined) {
76
- return DIGIT[base] * 10;
77
  }
78
 
79
- // Just "muoi" = 10
80
- if (base === "muoi") {
81
- return 10;
82
- }
83
-
84
- // "X tram Y" = X00 + Y
85
  if (next === "tram" && DIGIT[base] !== undefined) {
86
  var val = DIGIT[base] * 100;
87
  i += 2;
@@ -89,18 +105,41 @@ function parseNumberTokens(tokens) {
89
  val += DIGIT[toBaseForm(tokens[i])];
90
  i++;
91
  }
92
- return val;
 
 
 
 
 
93
  }
94
 
95
  // Single digit
96
  if (DIGIT[base] !== undefined) {
97
- return DIGIT[base];
98
  }
99
 
100
  i++;
101
  }
102
 
103
- return result || null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
  /**
@@ -119,38 +158,44 @@ export function normalizeVietnameseText(text) {
119
 
120
  if (!hasNum) return text.replace(/\s+/g, " ").trim();
121
 
122
- var words = text.split(/[\s,]+/);
 
123
  var output = [];
124
  var i = 0;
125
 
126
  while (i < words.length) {
127
  var w = words[i].trim().replace(/[,.!?;:)]+$/, "");
 
128
  var base = toBaseForm(w);
129
- var remaining = words.slice(i).map(function(t) { return t.trim().replace(/[,.!?;:)]+$/, ""); });
130
 
131
- // Try to parse a number phrase
132
- var parsed = parseNumberTokens(remaining);
133
- if (parsed !== null) {
134
- output.push(String(parsed));
135
- // Skip consumed words - find how many were consumed
136
- var consumed = 1;
137
- var testRem = remaining.slice(1);
138
- while (testRem.length && consumed <= 10) {
139
- var nextBase = toBaseForm(testRem[0]);
140
- if (nextBase === "muoi" || nextBase === "tram" || SCALE[nextBase] !== undefined || DIGIT[nextBase] !== undefined) {
141
- consumed++;
142
- testRem = testRem.slice(1);
143
- } else break;
 
 
 
 
 
 
 
144
  }
145
- i += consumed;
146
- continue;
147
  }
148
 
149
  output.push(words[i]);
150
  i++;
151
  }
152
 
153
- return output.join(" ").replace(/\s+/g, " ").trim();
154
  }
155
 
156
  /**
 
29
  // Scale words → multiplier
30
  var SCALE = { "muoi": 10, "tram": 100, "nghin": 1000, "ngan": 1000, "trieu": 1000000, "ty": 1000000000 };
31
 
32
+ /**
33
+ * Parse Vietnamese number phrases to digits.
34
+ * Handles: mot, hai, ba... (1-9)
35
+ * mot muoi, hai muoi... (10-90)
36
+ * mot muoi mot, hai muoi hai... (11-99)
37
+ * mot tram, hai tram... (100-900)
38
+ * mot nghin, hai nghin... (1000-2000000...)
39
+ */
40
+ function parseVietnameseNumber(text) {
41
+ var tokens = text.toLowerCase().split(/[\s,]+/).map(function(t) {
42
+ return t.replace(/[,.!?;:)]+$/, "").replace(/^[(\[]+/, "");
43
+ });
44
+
45
  var result = 0;
46
  var i = 0;
47
 
48
  while (i < tokens.length) {
49
  var base = toBaseForm(tokens[i]);
50
+ var next = i + 1 < tokens.length ? toBaseForm(tokens[i + 1]) : null;
 
51
 
52
+ // Large scale words (tỉ/ty, triệu, nghìn/ngàn)
53
+ if (base === "ty" || base === "tỉ") {
54
+ if (next === "muoi" || next === "tram" || SCALE[next] !== undefined || DIGIT[next] !== undefined) {
55
+ // "hai trieu" = 2000000, "ba muoi lam trieu" = 3,500,000
56
+ var group = parseGroup(tokens.slice(i + 1));
57
+ result += (group || 1) * SCALE.ty;
58
  i++;
59
+ while (i < tokens.length && (SCALE[toBaseForm(tokens[i])] || DIGIT[toBaseForm(tokens[i])])) i++;
60
  continue;
61
  }
62
+ result += SCALE.ty;
63
+ i++;
64
+ continue;
65
+ }
66
+
67
+ if (base === "trieu" || base === "triệu") {
68
+ var group = parseGroup(tokens.slice(i + 1));
69
+ result += (group || 1) * SCALE.trieu;
70
+ i++;
71
+ while (i < tokens.length && SCALE[toBaseForm(tokens[i])] !== undefined && SCALE[toBaseForm(tokens[i])] < SCALE.trieu) i++;
72
+ continue;
73
+ }
74
+
75
+ if (base === "nghin" || base === "ngan" || base === "nghìn" || base === "ngàn") {
76
+ var group = parseGroup(tokens.slice(i + 1));
77
+ result += (group || 1) * SCALE.nghin;
78
+ i++;
79
+ while (i < tokens.length && SCALE[toBaseForm(tokens[i])] !== undefined && SCALE[toBaseForm(tokens[i])] < SCALE.nghin) i++;
80
+ continue;
81
  }
82
 
83
  // "muoi mot" = 11
84
  if (base === "muoi" && (next === "mot" || next === "mơ")) {
85
+ return result + 11;
86
  }
87
 
88
+ // "X muoi" patterns (20-90)
89
  if (next === "muoi" && DIGIT[base] !== undefined) {
90
  var val = DIGIT[base] * 10;
91
  i += 2;
 
94
  if (ones === "mot" || ones === "mơ") val += 1;
95
  else if (DIGIT[ones] !== undefined) val += DIGIT[ones];
96
  }
97
+ return result + val;
 
 
 
 
 
98
  }
99
 
100
+ // "X tram" patterns (100-900)
 
 
 
 
 
101
  if (next === "tram" && DIGIT[base] !== undefined) {
102
  var val = DIGIT[base] * 100;
103
  i += 2;
 
105
  val += DIGIT[toBaseForm(tokens[i])];
106
  i++;
107
  }
108
+ return result + val;
109
+ }
110
+
111
+ // Just "muoi" = 10
112
+ if (base === "muoi") {
113
+ return result + 10;
114
  }
115
 
116
  // Single digit
117
  if (DIGIT[base] !== undefined) {
118
+ return result + DIGIT[base];
119
  }
120
 
121
  i++;
122
  }
123
 
124
+ return result > 0 ? result : null;
125
+ }
126
+
127
+ // Parse a group like "ba muoi" or "hai tram"
128
+ function parseGroup(tokens) {
129
+ if (!tokens || tokens.length === 0) return null;
130
+ var val = 0;
131
+ for (var i = 0; i < tokens.length; i++) {
132
+ var base = toBaseForm(tokens[i]);
133
+ if (SCALE[base] !== undefined && SCALE[base] >= 10) {
134
+ // Scale multipliers accumulate
135
+ if (i > 0 && DIGIT[toBaseForm(tokens[i-1])] !== undefined) {
136
+ val += DIGIT[toBaseForm(tokens[i-1])] * SCALE[base];
137
+ } else if (SCALE[base] === 10) val += 10;
138
+ } else if (DIGIT[base] !== undefined) {
139
+ val += DIGIT[base];
140
+ }
141
+ }
142
+ return val > 0 ? val : null;
143
  }
144
 
145
  /**
 
158
 
159
  if (!hasNum) return text.replace(/\s+/g, " ").trim();
160
 
161
+ // Try to find and replace number patterns
162
+ var words = text.split(/([\s,]+)/);
163
  var output = [];
164
  var i = 0;
165
 
166
  while (i < words.length) {
167
  var w = words[i].trim().replace(/[,.!?;:)]+$/, "");
168
+ if (!w) { output.push(words[i]); i++; continue; }
169
  var base = toBaseForm(w);
 
170
 
171
+ // Check if this starts a number phrase
172
+ var next = i + 1 < words.length ? toBaseForm(words[i + 1].trim().replace(/[,.!?;:)]+$/, "")) : "";
173
+
174
+ // Try to parse from this position
175
+ var remaining = [];
176
+ for (var j = i; j < words.length; j++) {
177
+ var wt = words[j].trim().replace(/[,.!?;:)]+$/, "");
178
+ if (wt && (DIGIT[toBaseForm(wt)] !== undefined || SCALE[toBaseForm(wt)] !== undefined)) {
179
+ remaining.push(wt);
180
+ } else break;
181
+ }
182
+
183
+ if (remaining.length >= 1) {
184
+ var parsed = parseVietnameseNumber(remaining.join(" "));
185
+ if (parsed !== null) {
186
+ output.push(String(parsed));
187
+ i += remaining.length;
188
+ // Skip any whitespace tokens
189
+ while (i < words.length && !words[i].trim()) i++;
190
+ continue;
191
  }
 
 
192
  }
193
 
194
  output.push(words[i]);
195
  i++;
196
  }
197
 
198
+ return output.join("").replace(/\s+/g, " ").trim();
199
  }
200
 
201
  /**