(text: string, counts: Map<string, number>)
| 197 | } |
| 198 | |
| 199 | function collectWords(text: string, counts: Map<string, number>): void { |
| 200 | const cleaned = text |
| 201 | .replace(/https?:\/\/\S+/gi, " ") |
| 202 | .replace(/[@#][\w_一-龥-]+/g, " ") |
| 203 | .replace(/[^\p{Script=Han}a-zA-Z0-9_+\-.]+/gu, " "); |
| 204 | |
| 205 | for (const match of cleaned.matchAll(/[a-zA-Z][a-zA-Z0-9_+\-.]{1,24}/g)) { |
| 206 | addWord(counts, match[0], 2); |
| 207 | } |
| 208 | for (const match of cleaned.matchAll(/\d{2,}[a-zA-Z%]?/g)) { |
| 209 | addWord(counts, match[0], 1); |
| 210 | } |
| 211 | |
| 212 | const hanParts = cleaned.match(/[\p{Script=Han}]{2,}/gu) || []; |
| 213 | for (const part of hanParts) { |
| 214 | if (part.length <= 4) { |
| 215 | addWord(counts, part, 3); |
| 216 | continue; |
| 217 | } |
| 218 | for (let size = 2; size <= 5; size++) { |
| 219 | for (let i = 0; i <= part.length - size; i++) { |
| 220 | const word = part.slice(i, i + size); |
| 221 | const edgeBonus = i === 0 || i === part.length - size ? 1 : 0; |
| 222 | addWord(counts, word, size <= 3 ? 1 + edgeBonus : 2 + edgeBonus); |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | function buildWordItems(counts: Map<string, number>): WordItem[] { |
| 229 | const entries = pruneOverlappingWords([...counts.entries()]) |
no test coverage detected