// Python 语义的小工具:原仓库是 Python,几处字符串 / 正则行为与 JS 不同,照 Python 的来。 /** len(s):按 Unicode 码点数,不按 UTF-16 码元。 */ export function cpLen(s: string): number { let n = 0; for (const _ of s) n++; return n; } /** s[:n]:按码点切。 */ export function cpSlice(s: string, n: number): string { if (s.length <= n) return s; // 码元数不超过 n,码点数更不会超过 return Array.from(s).slice(0, n).join(""); } /** str.splitlines()(不保留行尾)。 */ export function splitlines(s: string): string[] { if (s === "") return []; const parts = s.split(/\r\n|[\n\r\v\f\x1c\x1d\x1e\x85\u2028\u2029]/); if (parts.length > 0 && parts[parts.length - 1] === "") parts.pop(); return parts; } /** round(x, n):结果只用于展示,四舍五入到 n 位即可(不追究 Python 的银行家舍入)。 */ export function pyRound(x: number, n: number): number { const f = 10 ** n; return Math.round(x * f) / f; } // Python 的 \w 是 Unicode 的(字母 L*、数字 N*、下划线,不含组合符 M*);JS 的 \b 只认 ASCII。把 \b 换成按 Unicode 判的边界。 const W = "[\\p{L}\\p{N}_]"; const UNICODE_BOUNDARY = `(?:(?<=${W})(?!${W})|(? { return v && typeof v === "object" && !Array.isArray(v) ? (v as Record) : {}; } /** 各个检测器里的 _join_text:把 content 里所有 text 块拼起来。 */ export function joinText(content: unknown): string { if (!Array.isArray(content)) return ""; const parts: string[] = []; for (const b of content) { if (b && typeof b === "object" && (b as Record)["type"] === "text") { const t = (b as Record)["text"]; if (typeof t === "string") parts.push(t); } } return parts.join(""); } /** statistics.mean / pstdev。 */ export function mean(xs: readonly number[]): number { return xs.reduce((a, b) => a + b, 0) / xs.length; } export function pstdev(xs: readonly number[]): number { const mu = mean(xs); return Math.sqrt(xs.reduce((a, x) => a + (x - mu) ** 2, 0) / xs.length); }