如何基于用户自定义格式令牌准确解析字符串提取信息?
问题描述
需要根据自定义令牌格式的模板,从输入字符串中提取对应信息,示例如下:
- 模板格式:
#artist# - #song# [#id#] - 输入字符串:
Taylor Swift - Anti-Hero [ID123]
目标是正确提取艺术家(artist)、歌曲(song)与ID信息。
当前实现代码如下:
let format = "#artist# - #song# [#id#]"; let split = format.split(/#\w*#/); for(let i = 0; i < split.length; i++) { if (split[i] !== '') { let rep = split[i].split('').map(x => `\\${x}`).join(''); format = format.replace(split[i], rep); } } format = format.replace('#artist#', '([\\w\\s]*)').replace('#song#', '([\\w\\s]*)').replaceAll('#ignore#', '([\\w\\s]*)'); let test = new RegExp(format, 'g'); let res = 'Taylor Swift - AntiHero [ID123]'.matchAll(test);
存在以下问题:
- 当歌曲名包含连字符(如
Anti-Hero)时,使用([\w\s]*)会因为连字符不在匹配范围内导致匹配失败 - 如果ID外围的方括号被移除(此时方括号属于ID内容),原代码会解析失效
- 格式替换过程中存在匹配冲突,比如空格会匹配已转义替换的
' - '部分 - 非单词/空格的字符会破坏令牌的搜索逻辑
优化实现方案
可以采用先解析模板中的静态片段与令牌,再动态构建正则表达式的方式解决上述问题,具体实现如下:
function parseWithTemplate(template, input) { // 匹配所有令牌和静态文本片段 const tokenRegex = /(#\w+#)|([^#]+)/g; const regexParts = []; const tokenNames = []; let match; while ((match = tokenRegex.exec(template)) !== null) { if (match[1]) { // 提取令牌名称(去除前后#) const name = match[1].slice(1, -1); tokenNames.push(name); // 添加非贪婪捕获组,适配任意字符匹配 regexParts.push('(.*?)'); } else { // 转义静态文本中的正则特殊字符(如-、[、]等) const escapedText = match[2].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); regexParts.push(escapedText); } } // 构建完整正则,开启单行模式确保.能匹配换行符 const fullRegex = new RegExp(`^${regexParts.join('')}$`, 's'); const matchResult = input.match(fullRegex); if (!matchResult) return null; // 将捕获结果与令牌对应,返回结构化对象 const result = {}; tokenNames.forEach((token, index) => { result[token] = matchResult[index + 1].trim(); // 可选:去除内容前后空格 }); return result; } // 测试用例 const template = "#artist# - #song# [#id#]"; const input1 = "Taylor Swift - Anti-Hero [ID123]"; const input2 = "Taylor Swift - Anti-Hero ID123]"; // 移除左侧方括号 const input3 = "Taylor Swift - Anti-Hero [ID123"; // 移除右侧方括号 console.log(parseWithTemplate(template, input1)); // { artist: 'Taylor Swift', song: 'Anti-Hero', id: 'ID123' } console.log(parseWithTemplate(template, input2)); // { artist: 'Taylor Swift', song: 'Anti-Hero', id: 'ID123]' } console.log(parseWithTemplate(template, input3)); // { artist: 'Taylor Swift', song: 'Anti-Hero', id: 'ID123' }
方案优势
- 自动处理静态文本的正则转义,避免手动转义的疏漏
- 使用非贪婪匹配
(.*?),支持匹配包含连字符、特殊符号在内的任意内容,解决原方案的字符范围限制问题 - 精准分离令牌与静态文本,彻底避免替换冲突
- 当模板中的静态标记(如ID的方括号)缺失时,会自动将缺失部分纳入令牌匹配内容,符合实际需求
内容的提问来源于stack exchange,提问作者Tristan
相关产品推荐
相关产品推荐

