Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 2x 2x 3309x 2x 407x 407x 407x 407x 407x 407x 407x 1212x 218x 218x 218x 994x 504x 504x 490x 490x 407x | import * as str from './str';
import * as tok from './tok';
const tokenRegex = /[\p{L}\p{N}\p{M}]+|\s+|[^\p{L}\p{N}\p{M}\s]/gu;
/**
* Splits text into a token stream that concatenates back to the input exactly:
* maximal runs of word characters (`\p{L}\p{N}\p{M}`), maximal runs of
* whitespace, and every other character as its own token (surrogate pairs kept
* whole).
*/
export const words = (text: string): string[] => text.match(tokenRegex) ?? [];
/**
* Word-level diff: tokenizes both strings, diffs the token sequences, and maps
* the result back to a character-level {@link str.Patch} whose operation
* boundaries always fall on token boundaries. Composes with everything in
* `str` and `optimize`.
*
* @param src Old string.
* @param dst New string.
* @param tokenize Tokenizer; must partition its input exactly. Defaults to
* {@link words}.
* @returns A {@link str.Patch} aligned to token boundaries.
*/
export const diff = (src: string, dst: string, tokenize: (text: string) => string[] = words): str.Patch => {
const a = tokenize(src);
const b = tokenize(dst);
const patch = tok.diff(a, b);
const result: str.Patch = [];
let si = 0;
let di = 0;
for (const [type, count] of patch) {
if (type === str.PATCH_OP_TYPE.EQL) {
result.push([str.PATCH_OP_TYPE.EQL, a.slice(si, si + count).join('')]);
si += count;
di += count;
} else if (type === str.PATCH_OP_TYPE.DEL) {
result.push([str.PATCH_OP_TYPE.DEL, a.slice(si, si + count).join('')]);
si += count;
} else {
result.push([str.PATCH_OP_TYPE.INS, b.slice(di, di + count).join('')]);
di += count;
}
}
return result;
};
|