| 64 | */ |
| 65 | |
| 66 | export function regexToGlob(reStr: string): string | null { |
| 67 | let i: number = 0; // Current cursor in input / 输入游标位置 |
| 68 | const n: number = reStr.length; // Input length / 输入长度 |
| 69 | const out: string[] = []; // Accumulated glob pieces / 结果片段累积 |
| 70 | |
| 71 | // Set of regex special chars used to detect literals vs operators |
| 72 | // 正则特殊字符集合,用于区分字面量与操作符 |
| 73 | const REGEX_SPECIAL: Set<string> = new Set([".", "^", "$", "|", "(", ")", "[", "]", "{", "}", "?", "+", "*", "\\"]); |
| 74 | |
| 75 | // Map escaped chars into safe glob literal output. |
| 76 | // 将转义字符映射为可安全输出到 glob 的字面量: |
| 77 | // - '\\*' / '\\?' → '?'(单字符近似) |
| 78 | // - others → 原字符(如 '.'、'/') |
| 79 | function escapeGlobLiteral(ch: string): string { |
| 80 | if (ch === "*" || ch === "?") return "?"; // cannot be literal in pure glob; approximate as one char |
| 81 | return ch; |
| 82 | } |
| 83 | |
| 84 | // Look ahead / 取当前字符(不前进) |
| 85 | function peek(): string { |
| 86 | return reStr[i] || ""; |
| 87 | } |
| 88 | // Consume current char / 取当前字符并前进 |
| 89 | function next(): string { |
| 90 | return reStr[i++] || ""; |
| 91 | } |
| 92 | // If next is ch, consume it and return true; else false |
| 93 | // 若下一个字符为 ch,则消费并返回 true,否则返回 false |
| 94 | function eatIf(ch: string): boolean { |
| 95 | if (peek() === ch) { |
| 96 | i++; |
| 97 | return true; |
| 98 | } |
| 99 | return false; |
| 100 | } |
| 101 | |
| 102 | // 量词修饰:懒惰/占有 '?','+' —— 在 glob 中等价,统一忽略 |
| 103 | function eatQuantMod(): void { |
| 104 | if (peek() === "?" || peek() === "+") next(); |
| 105 | } |
| 106 | |
| 107 | // Interface for parsed unit |
| 108 | // 单元接口 |
| 109 | interface Unit { |
| 110 | glob: string; |
| 111 | baseGlob: string; |
| 112 | canRepeat: boolean; |
| 113 | min: number; |
| 114 | isLiteral: boolean; |
| 115 | varLen: boolean; |
| 116 | } |
| 117 | |
| 118 | // ----- Helpers for common prefix/suffix on literal arms ----- |
| 119 | // 公共前后缀 |
| 120 | function lcp(strs: string[]): string { |
| 121 | if (strs.length === 0) return ""; |
| 122 | let p = strs[0]; |
| 123 | for (const s of strs.slice(1)) { |