一、一个"看起来很简单"的功能
简记往来最受欢迎的功能之一是"批量记礼"。
用户把纸上的礼单敲成文本,一次性粘贴进去:
张叔叔 800
李阿姨 500
表哥 1000
系统自动解析出姓名和金额,一次性生成所有记录。
看起来很简单,对吧?
但实际上,这个功能的正则表达式写了5版才稳定。
二、第一版:只支持"姓名 金额"
第一版我写了一个最简单的正则:
javascript
const reg = /^([^\d\s]+)\s+(\d+)$/
逻辑:匹配"非数字非空格的字符(姓名)+ 至少一个空格 + 数字(金额)"。
上线后,用户反馈来了:
"我输入'张叔叔800'为什么解析不了?"
"我输入'表哥1000.00'为什么报错?"
"我输入'李阿姨500(婚礼)'怎么办?"
第一版只支持最完美的"姓名 空格 金额"格式,但用户的真实输入五花八门。
三、第二版:支持无空格
既然用户可能不敲空格,那就让正则支持"姓名金额"的格式:
javascript
const reg = /^([^\d]+)\s*(\d+(?:\.\d+)?)$/
改动点:
\s*让空格变成"可有可无"(\d+(?:\.\d+)?)支持了带小数的金额
支持了"张叔叔800",但"王二小800"又成了新问题------正则把"二"也当成了数字的一部分。
四、第三版:明确匹配中英文
第三版用更精确的字符集替换了"排除数字"的偷懒写法:
javascript
const match = line.match(/^([\u4e00-\u9fa5a-zA-Z·]+)\s*([\d.]+)/)
改动点:
[\u4e00-\u9fa5a-zA-Z·]+明确匹配中文、英文和中间点(少数民族姓名)- 不再用"排除数字"这种偷懒写法
这次稳定了很多,但"李阿姨500(婚礼)"这种带备注的还是不行。
五、第四版:逐行独立解析 + 多格式尝试
第四版换了思路:逐个尝试不同的格式,哪个能匹配就用哪个。
javascript
function tryParse(line) {
line = line.trim()
// 尝试1:标准"姓名 金额"
let match = line.match(/^([\u4e00-\u9fa5a-zA-Z·]+)\s+([\d.]+)/)
if (match) return { name: match[1].trim(), amount: parseFloat(match[2]) }
// 尝试2:无空格"姓名金额"
match = line.match(/^([\u4e00-\u9fa5a-zA-Z·]+)([\d.]+)/)
if (match) return { name: match[1].trim(), amount: parseFloat(match[2]) }
// 尝试3:金额在末尾"任意内容 金额"
match = line.match(/([\d.]+)$/)
if (match) {
const namePart = line.replace(/([\d.]+)$/, '').trim()
if (namePart.length > 0) {
return { name: namePart, amount: parseFloat(match[1]) }
}
}
return null
}
这次覆盖了大部分场景,但个别边缘情况仍然解析失败。
六、第五版:容错 + 预览编辑
最终版的核心逻辑:
javascript
function parseBatch(text) {
const lines = text.split('\n').filter(l => l.trim())
const results = []
for (const line of lines) {
const parsed = tryParse(line)
if (parsed) {
results.push(parsed)
} else {
// 解析失败,标记为"待修正"
results.push({
error: true,
raw: line,
name: '',
amount: null
})
}
}
return results
}
同时在前端做了防抖处理------用户停止输入300ms后才触发解析,避免频繁计算。
核心教训: 不要追求一次性完美解析。给用户预览和修正的机会,比追求100%准确更重要。
第一版追求完美,结果连50%的输入都覆盖不了;第五版接受"不完美",反而覆盖了95%以上的真实输入场景。
七、5次迭代的总结
| 版本 | 策略 | 结果 |
|---|---|---|
| 第一版 | 只支持"姓名 金额" | 覆盖<50%,用户抱怨 |
| 第二版 | 支持无空格 | 覆盖约70%,中文数字问题 |
| 第三版 | 明确匹配字符集 | 覆盖约80%,备注问题 |
| 第四版 | 多格式尝试 | 覆盖约90%,边缘问题 |
| 第五版 | 容错+预览编辑 | 覆盖>95%,用户可修正 |
八、经验教训
不要试图用一个正则覆盖所有场景。 先把80%的常见场景处理好,剩下的通过产品设计让用户自己修正。
用户需要的是"帮我省90%的力,剩下10%我自己来",而不是"100%完美但只能处理50%的场景"。
下一篇,我们来聊聊批量记礼的防抖与预览编辑设计。
评论区聊聊:你处理用户输入不规范时,用了什么方案?