正则表达式空格后使用负前瞻的实现技巧——JSON5无引号键转换场景
解决正则匹配无引号JSON5键的问题
你的核心问题在于负前瞻的位置没有和空格后的键起始位置绑定,导致\s*匹配空格后,负前瞻的检查位置不对,误匹配了带引号键前的空格。这里有个关键技巧:把负前瞻放在空格之后,直接约束键名的起始字符,确保它不是引号,同时用更精准的匹配规则来捕获键名。
修正后的代码
var sample = ` unquoted: "this is the first", "quoted": "this is the second" `; // 修正后的正则:匹配行首空格,然后确保下一个字符不是引号,再捕获直到冒号的键名 var result = sample.replaceAll(/^\s*(?!")([^\s:][^:]*):/gm, '"$1":'); console.log(result); // 输出结果: // "unquoted": "this is the first", // "quoted": "this is the second"
正则解释
让我们拆解一下修正后的正则/^\s*(?!")([^\s:][^:]*):/gm:
^:结合m修饰符,匹配每行的开头\s*:匹配行首任意数量的空格(0个或多个,完美解决空格数量不确定的问题)(?!"):负前瞻,强制当前位置(空格之后)的下一个字符不是双引号,直接排除带引号的键([^\s:][^:]*):精准捕获无引号键名:[^\s:]:确保键名的第一个字符不是空格或冒号(避免匹配空内容或冒号本身)[^:]*:匹配直到冒号前的所有字符(覆盖JSON5允许的各类无引号键名,比如带下划线、连字符的标识符)
::匹配键名后的冒号
为什么之前的正则会出错?
你之前的/^\s*(?!")(.*?):/gm中,(?!")是在\s*匹配之后检查位置,但.*?的非贪婪匹配特性加上正则回溯,导致它误匹配了带引号键前的空格——\s*匹配行首空格后,(.*?)会继续匹配空格(虽然你不希望),直到冒号,此时(?!")的检查已经错过了引号的位置,自然无法正确排除带引号的键。
额外优化(贴合JSON5规范)
如果需要严格符合JSON5无引号键的标识符规则,可把[^\s:][^:]*替换为[a-zA-Z_$][a-zA-Z0-9_$]*,这是JSON5定义的合法无引号键格式。
内容的提问来源于stack exchange,提问作者Manngo
相关产品推荐
相关产品推荐

