如何替换保存为字符串的正则中的反斜杠,使其正常生效?
我有一个名称数组,使用正则/^\[.*?[ЁёА-я].*?\]/g可以过滤出开头方括号内仅包含西里尔字母的项(对应示例中test1的结果:数组前三个元素),这个正则本身能正常工作。但将它以文本形式存入sqlite3数据库后,取出的是字符串格式,需要把\替换为\\才能让正则重新生效。
我尝试了以下几种替换方法,但都没有达到预期效果:
.replace(/\\/g, '\\\\');.replace(/(?<!\\)\\(?!\\)/g, '\\\\');.replaceAll("\\", "\\\\");
测试代码如下:
let arr = [ '[Лорем ипсум долор] - Lorem ipsum dolor sit amet', '[Уллум велит ностер еи] sed do eiusmod tempor incididunt ut labore et dolore magna aliqua (X22)', '[Пауло темпор те меа] Duis aute irure dolor (20X)', 'Duis aute irure dolor (20X) [Пауло темпор те меа]', '[Lorem ipsum] sunt in culpa qui officia [Test]' ]; // 正常工作:存入数据库前的正则字面量 let reg1 = /^\[.*?[ЁёА-я].*?\]/g; let test1 = arr.filter(x => x.match(reg1)); // 正常工作:提前转义好的字符串正则 let reg2 = "^\\[.*?[ЁёА-я].*?\\]"; reg2 = new RegExp(reg2,'g'); let test2 = arr.filter(x => x.match(reg2)); // 正常工作:用String.raw创建的原生字符串正则 let reg3 = String.raw`^\[.*?[ЁёА-я].*?\]`; reg3 = new RegExp(reg3,'g'); let test3 = arr.filter(x => x.match(reg3)); // 无效:从数据库取出的原始字符串格式正则 let reg4 = '^\[.*?[ЁёА-я].*?\]'; reg4 = reg4.replace(/\\/g, '\\\\'); // reg4 = reg4.replace(/(?<!\\)\\(?!\\)/g, '\\\\'); // reg4 = reg4.replaceAll("\\", "\\\\"); reg4 = new RegExp(reg4,'g'); let test4 = arr.filter(x => x.match(reg4)); console.log({ test1 : test1, test2 : test2, test3 : test3, test4 : test4 });
正确结果应为数组的前三个元素,与test1、test2、test3的输出一致。请问如何处理从数据库取出的字符串形式正则(如示例中的reg4),才能让它生效并得到正确输出?
解决方案
问题的核心在于:当你把正则/^\[.*?[ЁёА-я].*?\]/g以文本形式存入数据库时,实际存储的字符串应该是^\[.*?[ЁёА-я].*?\],但在JavaScript中,直接写'^\[.*?[ЁёА-я].*?\]'时,\[会被JS解析为普通的[(因为\是转义字符),导致你的字符串里根本不存在\,所以所有替换\的操作都找不到目标,自然无效。
要解决这个问题,你可以参考以下几种方法:
方法1:修正存储逻辑,确保字符串完整性
存入数据库时,直接存储正则的原生字符串形式(比如用String.raw生成的字符串),或者用JSON.stringify处理后再存入,避免转义字符丢失。取出后直接使用即可:
// 存入时:JSON.stringify(String.raw`^\[.*?[ЁёА-я].*?\]`) let reg4 = JSON.parse('"^\\\\[.*?[ЁёА-я].*?\\\\]"'); reg4 = new RegExp(reg4, 'g'); let test4 = arr.filter(x => x.match(reg4));
方法2:手动还原转义(针对已丢失转义的字符串)
如果数据库中存储的字符串已经丢失了\(比如存储的是^[.*?[ЁёА-я].*?]),可以手动给方括号添加转义:
let reg4 = '^[.*?[ЁёА-я].*?]'; // 模拟从数据库取出的无转义字符串 reg4 = reg4.replace(/([\[\]])/g, '\\$1'); // 转义方括号 reg4 = new RegExp(reg4, 'g'); let test4 = arr.filter(x => x.match(reg4));
方法3:存储完整正则字符串,取出后重建
存入数据库时,使用正则的toString()方法获取包含修饰符的完整字符串(比如"/^\[.*?[ЁёА-я].*?\]/g"),取出后通过正则匹配提取主体和修饰符,再重建正则:
let regStr = "/^\\[.*?[ЁёА-я].*?\\]/g"; // 从数据库取出的完整正则字符串 const matchResult = regStr.match(/^\/(.*)\/([gimuy]*)$/); let reg4 = new RegExp(matchResult[1], matchResult[2]); let test4 = arr.filter(x => x.match(reg4));
内容的提问来源于stack exchange,提问作者user21473566

