正则匹配含间隔空格字符串并高亮:特殊语法正则失效求助
正则匹配高亮与字符串间隔空格兼容问题解决
问题背景
需要实现一个函数,接收任意正则表达式,在字符串中匹配所有结果并高亮。要求字符串每10个字符插入一个空格,但正则匹配时要忽略这些空格。当前使用<samp [innerHTML]="highlight(str, pattern)"></samp>(基于Bootstrap的samp标签设置字体),现有TypeScript代码仅支持纯字母/数字的正则(如LST、NSP),带特殊语法的正则(如L[ST]P、LS.+P、LS.{2,4}P)完全失效。
现有问题代码
public highlight(str: string, pattern: string) { let seqWithSpaces = this.insertSpaces(str, true); let patternWithSpaces = this.insertSpaces(pattern, false); return seqWithSpaces.replace(new RegExp(patternWithSpaces, "g"), match => { return '<span class="highlightText">' + match + '</span>'; }); } private insertSpaces(seq: string, isPatternSeq: boolean): string { let output: string = ""; if (!isPatternSeq) { output = seq.replace(/(.{10})/g,"$1 ") } else { output = seq.replace(/(.{1})/g,"$1\s*") } return output; }
解决方案
方案一:智能调整正则格式适配空格间隔
原代码的问题是给正则的每个字符都加了\s*,破坏了正则的特殊语法(比如字符组[ST]、量词+/{2,4})。正确做法是仅在正则的字面量字符之间插入\s*,保留特殊语法结构:
public highlight(str: string, pattern: string) { const spacedStr = this.insertSpaces(str, true); const processedPattern = this.processPatternForSpaces(pattern); return spacedStr.replace(new RegExp(processedPattern, "g"), match => { return `<span class="highlightText">${match}</span>`; }); } private insertSpaces(seq: string, isTargetStr: boolean): string { if (isTargetStr) { // 目标字符串每10字符加空格,最后去除多余空格 return seq.replace(/(.{10})/g, "$1 ").trim(); } return seq; } private processPatternForSpaces(pattern: string): string { // 匹配正则中的特殊语法片段:字符组、转义字符、元字符、量词等 const specialPartRegex = /(\[.*?\]|\\.|[\^$.*+?(){}|])/g; let processed = pattern.replace(specialPartRegex, (match) => { // 特殊片段直接保留,普通字面量字符前后加\s* return /(\[.*?\]|\\.|[\^$.*+?(){}|])/.test(match) ? match : `\\s*${match}\\s*`; }); // 合并连续的\s*,避免冗余 return processed.replace(/\\s\*\\s\*/g, "\\s*"); }
方案二:先匹配原字符串,再插入空格
彻底规避正则与空格的冲突:先在无空格的原始字符串上完成匹配和高亮标记,再插入间隔空格(跳过HTML标签):
public highlight(str: string, pattern: string) { const regex = new RegExp(pattern, "g"); const matchPositions: { start: number, end: number }[] = []; let match; // 收集所有匹配的起始/结束位置 while ((match = regex.exec(str)) !== null) { matchPositions.push({ start: match.index, end: match.index + match[0].length }); // 处理正则包含g标志时的lastIndex问题,避免无限循环 if (match[0].length === 0) regex.lastIndex++; } // 从后往前插入高亮标签,避免位置偏移 let markedStr = str; for (let i = matchPositions.length - 1; i >= 0; i--) { const { start, end } = matchPositions[i]; markedStr = `${markedStr.slice(0, start)}<span class="highlightText">${markedStr.slice(start, end)}</span>${markedStr.slice(end)}`; } // 插入每10字符的空格,跳过HTML标签内容 return this.insertSpacesWithTags(markedStr); } private insertSpacesWithTags(str: string): string { let result = ""; let charCount = 0; let inHtmlTag = false; for (const char of str) { if (char === '<') { inHtmlTag = true; result += char; continue; } if (char === '>') { inHtmlTag = false; result += char; continue; } if (inHtmlTag) { result += char; continue; } result += char; charCount++; // 每10个字符加空格,排除最后一个位置 if (charCount % 10 === 0 && charCount !== str.length) { result += ' '; } } return result.trim(); }
内容的提问来源于stack exchange,提问作者mintak
相关产品推荐
相关产品推荐

