正则演示组件(RegexTester)¶
类型:wiki(知识沉淀) 描述:让用户即改即看的正则测试折叠组件,避免抽象正则改完不知道效果 最后更新:2026-05-26(v0.10.13) 相关源码:
src/sections/settings/regex-tester.tsx使用位置:src/sections/settings/view/settings-view.tsx(邮箱/手机/社媒正则旁各一个)
是什么¶
折叠按钮 + textarea + 实时匹配结果 — 用户改正则字段时点开「演示」即可看效果。
邮箱正则: [_____________________________]
[🧪 演示邮箱提取 · 匹配 2 项] ▼
┌─ 测试 ─────────────────────────────┐
│ 测试文本(贴入 HTML/纯文本均可) │
│ ┌─────────────────────────────────┐ │
│ │ Contact: hello@acme.com, │ │
│ │ john_doe@sub.example.org │ │
│ └─────────────────────────────────┘ │
│ ✓ 匹配到 2 项: │
│ ┌──────────────────┐ │
│ │ hello@acme.com │ │
│ │ john_doe@sub.exa..│ │
│ └──────────────────┘ │
└────────────────────────────────────┘
为什么¶
正则太抽象,用户改完不知道效果。v0.10.13 之前的痛点:
- 用户改了
phoneRegex→ 跑一次任务 → 看结果发现不对 → 再改 → 再跑 → ... - 一轮调试 5 分钟,10 次就是 50 分钟。
加 RegexTester 后: - 改正则 → 点演示 → 0.1 秒看结果 → 继续改 → ...
关键代码¶
Props¶
interface Props {
regex: string; // 当前正则字符串
sampleDefault: string; // 默认示例文本(含「应匹配」+「应过滤」例子)
label?: string; // 折叠按钮文字
flags?: string; // 默认 'gi'
groupIndex?: number; // 默认 0(整体);手机 Tier 用 1
}
即改即看¶
const { matches, error } = useMemo(() => {
try {
const re = new RegExp(regex, flags);
const arr: string[] = [];
let m;
while ((m = re.exec(text)) !== null) {
const captured = m[groupIndex] ?? m[0];
if (captured && !arr.includes(captured)) arr.push(captured);
if (!re.global) break; // 防死循环
if (arr.length >= 50) break; // 上限
}
return { matches: arr, error: '' };
} catch (e) {
return { matches: [], error: e.message };
}
}, [regex, text, flags, groupIndex]);
失败友好¶
正则非法时显示红字 ⚠️ <message>,不抛错。这样用户敲到一半也不会崩。
用法示例¶
import { RegexTester, SAMPLE_EMAIL_TEXT } from '../regex-tester';
<RHFTextField name="emailRegex" />
<RegexTester
regex={(currentValues as any)?.emailRegex || DEFAULT_EMAIL_REGEX}
sampleDefault={SAMPLE_EMAIL_TEXT}
label="演示邮箱提取"
flags="gi"
/>
内置示例文本¶
每个示例都包含应匹配 + 应过滤的例子,让用户能看到过滤效果:
export const SAMPLE_EMAIL_TEXT = `Contact us:
- Sales: sales@acme.com
- Support: help@sub.example.org
<a data-cfemail="...">Protected</a> ← Cloudflare 解码示例
(spam to filter)
test@test.com ← 内置黑名单应过滤
icon.png@cdn-cgi/l/email-protection ← 噪音模式应过滤
`;
export const SAMPLE_PHONE_TEXT = `Call us!
<a href="tel:+1-415-555-1234">Click</a> ← Tier 1
Phone: +44 20 7946 0958 ← Tier 2
Free text: +1 234 567 8901 ← Tier 3
ISBN 9780123456789 ← 应被长度过滤
Order #1234567890 ← 应被黑名单过滤
`;
export const SAMPLE_SOCIAL_TEXT = `...含正面 + 反面例子...`;
已踩坑(已修复)¶
⚠️ 坑 1:useMemo key 漏字段¶
最初 key 只放了 regex —— 用户改 text 不重算。
修复:key 加 flags + groupIndex + text 全部依赖。
⚠️ 坑 2:re.global 检测不准¶
不是 re.global flag 而是 flags.includes('g')。修复同上。
⚠️ 坑 3:匹配项太多导致 UI 卡顿¶
上限 50 项 + while 里 arr.length >= 50 break。
修改这块时要 / 不要做什么¶
- ✅ 加新示例文本 → export
SAMPLE_<类型>_TEXT,含正反例 - ✅ 加新 prop → keep optional,默认走旧行为
- ❌ 不要去掉错误友好(try/catch) — 用户敲到一半时正则不合法是常态
- ❌ 不要去掉 50 项上限(防 UI 卡顿)
版本里程碑¶
| 版本 | 事件 |
|---|---|
| v0.10.13 | 最初引入,邮箱/手机/社媒 3 处使用 |