需求:
在一个输入框里只能输入键值对的形式,单个键值对之间使用逗号隔开,形如 a:b,c:d,(键和值加不加引号都可以),或者 {"a":"b","c":"d"} ,这只是一种简单的输入,再复杂点就是嵌套 {a:b,c:[1,2,3],d:{a:b,c:[2,3]} },抑或者更深层次的嵌套,再再复杂点就是像下面这种请求头和请求体的键值对样式
Connection: Keep-Alive,
Date: Tue, 02 Jul 2019 10:18:26 GMT,
Set-Cookie: delPer=0; path=/; domain=.baidu.com,
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko)
不管嵌套多深,就只管校验最外边一层是否是键值对的形式。
对于校验是否是键值对的输入方式,可以使用JSON字符串的校验JSON.parse(),但是前提是要将普通字符串转换成JSON字符串,对于输入框的内容,不管写的多花里胡哨,对象嵌套层次有多深,只要键或者值不加引号,都只是一个普通字符串,并不是json字符串,json的方式无效,如果要求用户输入的时候加上引号,即"a":"b","c":"d"这种形式,就直接可以加上{}后,使用JSON.parse的方式,当然了,这是最简单也是最理想的方式,但是,用户输入的时候,加上引号,反而会很麻烦,用户体验并不是很好。
可能会有eval方法或者new Function的方式,但是a:b这种输入使用eval或者Function方法后,控制台会报错,显示b未定义,还是要再输入的时候给b加上引号,或者是拿到值之后,再加上引号,然后再校验。
那么问题回到给a:b的a和b也就是键和值加上双引号,然后再使用json的方法校验是否是键值对的输入。
1、简单的输入:a:b,b:c,或者是嵌套输入,甚至是更深层次的嵌套
value = value.replace(/(\w+)/g, '"$1"');
不管是否嵌套,嵌套有多深,每个键值对之间是使用逗号分开,键和值之间使用冒号,不考虑逗号,冒号,小括号,中括号,花括号,那么,只需要给每一个相连的字符(数字或者字母,字符之间没有特殊符号,)加上双引号就行,
输入:a:b,c:[1,2],d:{a:b,c:[2,13]},s:{1a:b,c:[111,2],d:{a11:11b,d:{a:b,d:{a:v,s:{a1q:v}}}}},这个嵌套了很多层
转换成为:{"a":"b","c":["1","2"],"d":{"a":"b","c":["2","13"]},"s":{"1a":"b","c":["111","2"],"d":{"a11":"11b","d":{"a":"b","d":{"a":"v","s":{"a1q":"v"}}}}}},当然,中间还有一步就是在经过正则匹配修改过的字符串两边加上花括号,经过json.parse()之后的结果为:
被成功转换成了json对象,那就说明,输入框的内容是键值对的形式
完整的过程为:
let value = text.value//拿到输入框的值
value = value.replace(/'|"/g, '');//不管用户加没加,先去掉字符串中的所有引号
value = value.replace(/(\w+)/g, '"$1"');//给每一个字符串加上引号
value = '{' + value + '}'//加上花括号,变成json字符串
console.log(JSON.parse(value) );//使用json校验是否是键值对的形式,如果不是,则这一行会报错,实际判断过程中,使用try{}catch抛出异常,程序就不会崩
如果考虑键或者值中有特殊符号,比如常见的中划线( - )则按照如下规则匹配
value = value.replace(/(\w+-?\w+|\w+)/g, '"$1"');
2、更复杂的输入,就是如下这样,
Connection: Keep-Alive,
Date: Tue, 02 Jul 2019 10:18:26 GMT,
Set-Cookie: delPer=0; path=/; domain=.baidu.com,
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko)
其实这就是常见的http请求头,键和值中包含着多种符号,其他的特殊符号还比较好处理,但是,在这一句中Date: Tue, 02 Jul 2019 10:18:26 GMT,包含了区分单个键值对的逗号,还包含了对象之间的冒号,上边说的方法就无效了,而且,即使是写个方法进行区分,但是,还是不好区分键和值的组合:
比如:
(Date): (Tue, 02 Jul 2019 10:18:26 GMT),
(Date): (Tue), (02 Jul 2019 10):(18:26 GMT),
(Date: Tue), (02 Jul 2019 10:18):(26 GMT),
等等,这些组合,肉眼可以很容易区分,但是写成程序,却是不好判断,大家可以去看看浏览器控制栏里的请求头和请求体,其实都是很复杂的,但是对于请求体来说,又是合法的。目前还没有想到好的办法去校验。
那么,回到需求,还是让用户输入的时候自觉加上引号吧,也就是写成这样,如果不要求这么复杂的输入,那么可以使用第一种方法
"Date": "Tue, 02 Jul 2019 10:18:26 GMT",
如果大家有什么好的方法,欢迎留言告知,不胜感激。