mirror of
https://github.com/Horizontal42/summarum.git
synced 2026-11-10 21:31:59 +03:00
split lexLine's number/date matching into named helpers
lexLine had grown into one long function trying dates, hex/bin/oct, grouped numbers, decimals and xrefs inline. Extracted each into a tryLex* helper with the same fallback order, so the driving loop reads as a priority list instead of nested ifs.
This commit is contained in:
parent
f634b1858e
commit
f2deaa1b94
1 changed files with 104 additions and 93 deletions
|
|
@ -34,25 +34,12 @@ function validDateMs(y: number, mo: number, d: number): number | null {
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lexLine(text: string, dateOrder: DateOrder = "dmy"): Lex[] {
|
function tryLexDate(rest: string, i: number, dateOrder: DateOrder): Lex | null {
|
||||||
const out: Lex[] = [];
|
|
||||||
let i = 0;
|
|
||||||
while (i < text.length) {
|
|
||||||
const ch = text[i];
|
|
||||||
if (ch === " " || ch === "\t" || ch === " ") {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const rest = text.slice(i);
|
|
||||||
|
|
||||||
if (ch >= "0" && ch <= "9") {
|
|
||||||
const iso = /^(\d{4})-(\d{2})-(\d{2})(?!\d)/.exec(rest);
|
const iso = /^(\d{4})-(\d{2})-(\d{2})(?!\d)/.exec(rest);
|
||||||
if (iso) {
|
if (iso) {
|
||||||
const ms = validDateMs(Number(iso[1]), Number(iso[2]), Number(iso[3]));
|
const ms = validDateMs(Number(iso[1]), Number(iso[2]), Number(iso[3]));
|
||||||
if (ms !== null) {
|
if (ms !== null) {
|
||||||
out.push({ type: "date", raw: iso[0], start: i, end: i + iso[0].length, dateMs: ms });
|
return { type: "date", raw: iso[0], start: i, end: i + iso[0].length, dateMs: ms };
|
||||||
i += iso[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const dm = SLASH_DOT_DATE_RE.exec(rest);
|
const dm = SLASH_DOT_DATE_RE.exec(rest);
|
||||||
|
|
@ -64,33 +51,29 @@ export function lexLine(text: string, dateOrder: DateOrder = "dmy"): Lex[] {
|
||||||
const y = Number(dm[4]);
|
const y = Number(dm[4]);
|
||||||
const ms = dayFirst ? validDateMs(y, b, a) : validDateMs(y, a, b);
|
const ms = dayFirst ? validDateMs(y, b, a) : validDateMs(y, a, b);
|
||||||
if (ms !== null) {
|
if (ms !== null) {
|
||||||
out.push({ type: "date", raw: dm[0], start: i, end: i + dm[0].length, dateMs: ms });
|
return { type: "date", raw: dm[0], start: i, end: i + dm[0].length, dateMs: ms };
|
||||||
i += dm[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
if (ch >= "0" && ch <= "9") {
|
|
||||||
|
function tryLexBaseNumber(rest: string, i: number): Lex | null {
|
||||||
const hex = /^0[xX][0-9a-fA-F]+/.exec(rest);
|
const hex = /^0[xX][0-9a-fA-F]+/.exec(rest);
|
||||||
if (hex) {
|
if (hex) {
|
||||||
out.push({ type: "num", raw: hex[0], start: i, end: i + hex[0].length, value: new Decimal(parseInt(hex[0], 16)), repr: "hex" });
|
return { type: "num", raw: hex[0], start: i, end: i + hex[0].length, value: new Decimal(parseInt(hex[0], 16)), repr: "hex" };
|
||||||
i += hex[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const bin = /^0[bB][01]+/.exec(rest);
|
const bin = /^0[bB][01]+/.exec(rest);
|
||||||
if (bin) {
|
if (bin) {
|
||||||
out.push({ type: "num", raw: bin[0], start: i, end: i + bin[0].length, value: new Decimal(parseInt(bin[0].slice(2), 2)), repr: "binary" });
|
return { type: "num", raw: bin[0], start: i, end: i + bin[0].length, value: new Decimal(parseInt(bin[0].slice(2), 2)), repr: "binary" };
|
||||||
i += bin[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const oct = /^0[oO][0-7]+/.exec(rest);
|
const oct = /^0[oO][0-7]+/.exec(rest);
|
||||||
if (oct) {
|
if (oct) {
|
||||||
out.push({ type: "num", raw: oct[0], start: i, end: i + oct[0].length, value: new Decimal(parseInt(oct[0].slice(2), 8)), repr: "octal" });
|
return { type: "num", raw: oct[0], start: i, end: i + oct[0].length, value: new Decimal(parseInt(oct[0].slice(2), 8)), repr: "octal" };
|
||||||
i += oct[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
if (ch >= "0" && ch <= "9") {
|
|
||||||
|
function tryLexDecimalNumber(rest: string, i: number): Lex | null {
|
||||||
let raw: string | null = null;
|
let raw: string | null = null;
|
||||||
let cleaned = "";
|
let cleaned = "";
|
||||||
const sp = NUM_SPACE_GROUPED_RE.exec(rest);
|
const sp = NUM_SPACE_GROUPED_RE.exec(rest);
|
||||||
|
|
@ -111,37 +94,65 @@ export function lexLine(text: string, dateOrder: DateOrder = "dmy"): Lex[] {
|
||||||
cleaned = raw;
|
cleaned = raw;
|
||||||
}
|
}
|
||||||
if (raw) {
|
if (raw) {
|
||||||
out.push({ type: "num", raw, start: i, end: i + raw.length, value: new Decimal(cleaned), repr: "decimal" });
|
return { type: "num", raw, start: i, end: i + raw.length, value: new Decimal(cleaned), repr: "decimal" };
|
||||||
i += raw.length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
if (ch === "." && /^\.\d/.test(rest)) {
|
|
||||||
const m = /^\.\d+/.exec(rest)!;
|
|
||||||
out.push({ type: "num", raw: m[0], start: i, end: i + m[0].length, value: new Decimal(m[0]), repr: "decimal" });
|
|
||||||
i += m[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ch === "@") {
|
function tryLexDotNumber(rest: string, i: number): Lex | null {
|
||||||
|
if (/^\.\d/.test(rest)) {
|
||||||
|
const m = /^\.\d+/.exec(rest)!;
|
||||||
|
return { type: "num", raw: m[0], start: i, end: i + m[0].length, value: new Decimal(m[0]), repr: "decimal" };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryLexXRef(rest: string, i: number): Lex | null {
|
||||||
const bracket = /^@\[([^\]]+)\]\.([\p{L}_][\p{L}\d_]*)/u.exec(rest);
|
const bracket = /^@\[([^\]]+)\]\.([\p{L}_][\p{L}\d_]*)/u.exec(rest);
|
||||||
if (bracket) {
|
if (bracket) {
|
||||||
out.push({ type: "xref", raw: bracket[0], start: i, end: i + bracket[0].length, sheet: bracket[1].trim(), key: bracket[2] });
|
return { type: "xref", raw: bracket[0], start: i, end: i + bracket[0].length, sheet: bracket[1].trim(), key: bracket[2] };
|
||||||
i += bracket[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
const bare = /^@([\p{L}_][\p{L}\d_]*)\.([\p{L}_][\p{L}\d_]*)/u.exec(rest);
|
const bare = /^@([\p{L}_][\p{L}\d_]*)\.([\p{L}_][\p{L}\d_]*)/u.exec(rest);
|
||||||
if (bare) {
|
if (bare) {
|
||||||
out.push({ type: "xref", raw: bare[0], start: i, end: i + bare[0].length, sheet: bare[1], key: bare[2] });
|
return { type: "xref", raw: bare[0], start: i, end: i + bare[0].length, sheet: bare[1], key: bare[2] };
|
||||||
i += bare[0].length;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tryLexWord(rest: string, i: number): Lex | null {
|
||||||
const word = WORD_RE.exec(rest);
|
const word = WORD_RE.exec(rest);
|
||||||
if (word) {
|
if (word) {
|
||||||
out.push({ type: "word", raw: word[0], start: i, end: i + word[0].length });
|
return { type: "word", raw: word[0], start: i, end: i + word[0].length };
|
||||||
i += word[0].length;
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function lexLine(text: string, dateOrder: DateOrder = "dmy"): Lex[] {
|
||||||
|
const out: Lex[] = [];
|
||||||
|
let i = 0;
|
||||||
|
while (i < text.length) {
|
||||||
|
const ch = text[i];
|
||||||
|
if (ch === " " || ch === "\t" || ch === " ") {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const rest = text.slice(i);
|
||||||
|
|
||||||
|
let lex: Lex | null = null;
|
||||||
|
if (ch >= "0" && ch <= "9") {
|
||||||
|
lex = tryLexDate(rest, i, dateOrder) || tryLexBaseNumber(rest, i) || tryLexDecimalNumber(rest, i);
|
||||||
|
} else if (ch === ".") {
|
||||||
|
lex = tryLexDotNumber(rest, i);
|
||||||
|
} else if (ch === "@") {
|
||||||
|
lex = tryLexXRef(rest, i);
|
||||||
|
}
|
||||||
|
if (!lex) {
|
||||||
|
lex = tryLexWord(rest, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lex) {
|
||||||
|
out.push(lex);
|
||||||
|
i += lex.raw.length;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue