Skip to content

Instantly share code, notes, and snippets.

@tjjfvi
Last active March 1, 2023 20:09
Show Gist options
  • Save tjjfvi/80d1379437e9192379c6e81b7396c2bc to your computer and use it in GitHub Desktop.
Save tjjfvi/80d1379437e9192379c6e81b7396c2bc to your computer and use it in GitHub Desktop.
A regex matching only ISO8601-formatted dates representing weekdays
// @ts-nocheck
const charset = [..."0123456789-"];
let visitState,
x,
obj,
selfPath,
initialPath,
path;
const str = JSON.stringify;
const initial = 0;
const accept = 1;
const next = 2;
const testDfa = (dfa, i) =>
dfa[accept]([...i].reduce((a, b) => dfa[next](a)(b), dfa[initial]));
const dfaToString = (dfa, paths = { s: { [str(dfa[initial])]: "" } }) => (
(visitState = (state) =>
paths[x = str(state)] = paths[x] ||
(paths[x] = {},
charset.reduce((obj, char, nextState) => (
nextState = dfa[next](state)(char),
visitState(nextState),
obj[x = str(nextState)] = (obj[x] || "[]").slice(0, -1) +
(char == "\\" || char == "]" ? "\\" : "") + char + "]",
dfa[accept](state) && (obj.e = ""),
obj
), {})))(dfa[initial]),
Object.keys(paths).map((removeState) =>
removeState != "s" && (
obj = paths[removeState],
selfPath = obj[removeState],
delete obj[removeState],
delete paths[removeState],
Object.keys(paths).map((a) =>
(
initialPath = paths[a][removeState]
) !== {}.x &&
delete paths[a][removeState] &&
Object.keys(obj).map((b) => (
path = initialPath + (selfPath ? `(${selfPath})*` : "") + obj[b],
paths[a][b] = paths[a][b] != {}.x
? `(?:${paths[a][b]}|${path})`
: path
))
)
)
),
paths.s.e || "[]"
);
const mlts = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const mltslp = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
const weekday = [
[0, 0, 4, 0],
(state) => !!(state && state[2] < 5),
(state) => (char) => {
if (!state) return null;
let [i, lp, dm7, c] = state;
if (i === 10) return null;
if (char === "-") {
return i === 4 || i === 7 ? [i + 1, lp, dm7, c] : null;
}
if (i === 4 || i === 7) return null;
if (i === 0 || i === 2) {
return [i + 1, lp, dm7, +char];
}
if (i === 1) {
let cy = c * 10 + +char;
return [i + 1, cy % 4, dm7, 0];
}
if (i === 3) {
let y = c * 10 + +char;
let le = +(y % 4 === 0 && (y !== 0 || lp === 0));
return [
i + 1,
le,
(dm7 + lp * 5 + y + ((y - 1) / 4 | 0) + +!(lp === 0 && y === 0)) % 7,
0,
];
}
if (i === 5) {
if (char !== "0" && char !== "1") return null;
return [i + 1, lp, dm7, +char];
}
if (i === 6) {
let m = c * 10 + +char;
if (m < 1 || m > 12) return null;
let mls = lp ? mltslp : mlts;
return [
i + 1,
mls[m - 1],
(dm7 + mls.slice(0, m - 1).reduce((a, b) => a + b, 0)) % 7,
0,
];
}
if (i === 8) {
if (+char > 3) return null;
return [i + 1, lp, dm7, +char];
}
if (i === 9) {
let d = c * 10 + +char;
if (d < 1 || d > lp) return null;
return [i + 1, 0, (dm7 + d) % 7, 0];
}
},
];
const regexSource = `^${dfaToString(weekday)}$`;
Deno.writeTextFile("weekday-regex", `/${regexSource}/`);
const rgx = new RegExp(regexSource);
const trues = [
"2023-02-27",
"2023-02-28",
"2023-03-01",
"2023-03-02",
"2023-03-03",
"2023-03-06",
"2023-03-07",
"1940-07-12",
"1927-02-23",
"1928-02-23",
];
console.log("true:");
for (const x of trues) console.log(x, test(x));
console.log("\nfalse:");
const falses = [
"2023-02-26",
"2023-03-04",
"2023-03-05",
"2023-02-29",
"2023-12-90",
"2020-20-20",
"2023-2-27",
"2023-2-2",
"----------",
"0001-01-01",
"1940-07-13",
"1927-02-26",
"1929-02-23",
];
for (const x of falses) console.log(x, test(x));
function test(x) {
// return rgx.test(x);
return testDfa(weekday, x);
}
This file has been truncated, but you can view the full file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment