检查JSON LIKE字符串是否有效 - JS正则表达式

3

我有一个CLI应用程序,用户提供JSON。我需要检查JSON是否有效。我发现以下内容可能非常有用:

function isJsonValid(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

但是当我调试我的应用程序时,我注意到一个小问题,即命令中所有的引号"和单引号'以及空格都被剥离了。 因此json如下:

{
    "key1": "value1",
    "key2": "value2"
} 

被更改为以下内容:

{key1:value1,key2:value2}

我需要一个正则表达式来检查这个已剥离的JSON是否有效。因此,结果应该看起来像这样:
re.test({key1:value1,key2:value2}) // true
re.test({key1:value1}) // true
re.test({key1:value1,}) // false, extra comma
re.test({key1:value1, key2}) // false, missing value of key2
re.test({key1:value1, key2:value2) // false, missing closing }
re.test({key1:value1, key2:value2}}) // false, extra closing }

有人可以帮我处理正则表达式部分吗?很不幸,这真的不是我的强项。


2
“Stripped” JSON 不再是 JSON,但如果这是您的输入并且您想按原样验证它,您只需要测试仅包含顶级 key:value 对的简单情况,还是必须允许嵌套对象和/或数组? - nnnnnn
是的,不会有嵌套数组。因此,我需要测试JSON是否如下所示: { - 开始括号,key + : + value + 结束括号 }。而key:value部分可以重复多次,并且应该用逗号分隔。 - Andurit
我在这里漏掉了什么重要的东西吗?如果您的函数返回 true,则传递的 JSON 是有效的,如果它返回 false,则发生了错误,JSON 无效。为什么要重新检查呢? - Teemu
@Teemu - OP实际上没有JSON,输入类似于JSON但没有所有引号。 - nnnnnn
我认为你需要把注意力放在你与JSON有的小问题上,而不是评估那个剥离版本,那里肯定出了问题。你能告诉我们str变量是如何传递给isJsonValid函数的吗?-- @Teemu,该函数总是返回false,因为str不是JSON - gmo
2个回答

4

以下是正则表达式:

^{(([a-zA-Z0-9]+:[a-zA-Z0-9]+)(,[a-zA-Z0-9]+:[a-zA-Z0-9]+)*)?}$

在Regex101.com上检查您的示例

该网站可以帮助您测试和调试正则表达式。

点赞,感谢您的好回答。我标记 nnnn 为正确,因为它更加复杂且他先回答。但是非常感谢您。 - Andurit
1
我很高兴能够帮助!无论是否标记,我都很高兴你得到了最佳解决方案。 - Zirbo Filip

3

如我在上面的评论中提到的那样,“去除掉格式”的JSON当然不再是JSON。您已确认无需担心嵌套对象或数组,只需要一个由花括号包围的简单的键:值对列表。

因此,以下正则表达式假定每个键和值都由“单词”字符组成,使用正则表达式\w,它等同于[A-Za-z0-9_]

var re = /^\{\w+:\w+(,\w+:\w+)*\}$/;

显然,如果你想要改变允许用作键名和值的字符,你可以将每个\w替换为[A-Za-z0-9_],根据需要添加或删除允许使用的字符。

编辑:在评论中提到允许在键名和值中使用.。因此,在正则表达式上使用不区分大小写的i标志:

var re = /^\{[A-Z0-9._]+:[A-Z0-9._]+(,[A-Z0-9._]+:[A-Z0-9._]+)*\}$/i;

但是你可能希望在所有部分之间允许可选的空格,因此我建议在所有令牌之间添加\s*

var re = /^\s*\{\s*[A-Z0-9._]+\s*:\s*[A-Z0-9._]+\s*(,\s*[A-Z0-9._]+\s*:\s*[A-Z0-9._]+\s*)*\}\s*$/i;

console.log( re.test('{key1:value1,key2:value2}') )   // true
console.log( re.test('{key1:value1}') )               // true
console.log( re.test(' { key1 : value1 , key2 : value2 ,  k3  :   v3  } ') ) // true
console.log( re.test(' { k.j.m : v.a2 , k2.a.b : v.32 ,  k3  :   v3  } ') ) // true
console.log( re.test('{key1:value1,}') )              // false, extra comma
console.log( re.test('{key1:value1, key2}') )         // false, missing value of key2
console.log( re.test('{key1:value1, key2:value2') )   // false, missing closing }
console.log( re.test('{key1:value1, key2:value2}}') ) // false, extra closing }

(请注意,我编辑的部分允许名称中有 . ,但我不想在每次添加更多要求时都返回更新我的答案。 如果您希望严格保持一行中仅一个 . 并且没有前导或尾随点,则只需应用与上面正则表达式相同的原理以使逗号起作用。)

嘿@nnnnnn,你能否考虑值或键不仅仅是简单的字符串,而可以是例如is.my.value(因此在它们之间添加点)? - Andurit
是的,我在我的答案中已经涵盖了这一点:用方括号中允许的字符列表替换每个\w - nnnnnn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接