js正则,要求匹配除指定字符外的其他所有字符

heath_learning
  • 1.3k

需求:取出下面字符串中的“学习”“2022”“看电影”“true”“打球”“null”,不能使用JSON.parse

let str = '["学习",2022,"看电影",true,"打球",null,{"hobbyA":123}]'

出这个需求的原因:想自己实现解析json字符串的功能,一开始想的是用正则来匹配,多层对象嵌套的json字符串用正则实现了,但遇到对象里有数组时发现用正则来匹配会误匹配,所以有了这个问题

回复
阅读 1.7k
7 个回答
✓ 已被采纳

题主的要求应该是只匹配数组里面的简单项,不能匹配复杂项(对象或者数组)
那思路应该是判断匹配项是不是在复杂项内部
因为复杂项的括号都是成对出现的,所以可以通过记录括号的数量来判断,实现如下

let str = '["学习",2022,"看电影",true,"打球",null,{"hobbyA": 1, "d": [123, "23", true], "abc": {"b": "1", "c": true}}]'
// 先清除首尾的中括号
str = str.replace(/^\[|\]$/g, '')
// 最后的匹配结果
const arr = [];
// 记录当前括号的数量
let count = 0;
let res = null;
// 匹配不包含逗号的所有字符
const reg = /[^,]+/g
// 左边括号
const reg1 = /\{|\[/g;
// 右边括号
const reg2 =  /\}|\]/g
while(res = reg.exec(str)) {
  const str = res[0];
  const match1 = str.match(reg1);
  const match2 = str.match(reg2);
  if (match1 || match2) {
    // 如果匹配到了左括号就+数量,匹配到右括号就-数量
    count += (match1 ? match1.length : match2 ? -match2.length : 0);
  } else if (count == 0) {
    // 如果count为0,说明前面不存在未结束的括号
    arr.push(str)
  }
}
console.log(arr)
'["学习",2022,"看电影",true,"打球",null,{"hobbyA":123}]'.match(/[^/[].*?,/g).map(s => s.replace(/"|,/g, ''))

这样符合你要求吗

如果只是为了完成题目,那么就当做字符串去处理。

毕竟你也没有说什么规则对吧。但是我猜你是想取基本类型。

image.png

split 比全用正则表达式清楚,同意的话请采纳。

let str = '["学习",2022,"看电影",true,"打球",null,{"hobbyA":123}]';

let str1 = str.replace(/{.*?}|\[|\]/g, '');
let arr = str1.split(',');
for (var i = 0; i < arr.length; i++ ) {
  if (arr[i]) console.log(arr[i].replace(/"(.+)"/, '$1'));
}
(function($str){
    let map = {
        '"' : false,
        '[]' : 0,
        '{}' : 0,
    };

    let arrMatch = [];
    let arr = [];

    let filter = function($match){
        if(map['"'] === true)
        {
            arr.push($match);
            return true;
        }

        if(arr.length > 0)
        {
            arrMatch.push(arr.join(''));
            arr = [];
        }

        return false;
    };
    $str.replace(/./g, function($match){
        switch($match)
        {
            case '[':
                if(filter($match) === false)
                    map['[]'] ++;
                break;
            case ']':
                if(filter($match) === false)
                    map['[]'] --;
                break;
            case '{':
                if(filter($match) === false)
                    map['{}'] ++;
                break;
            case '}':
                if(filter($match) === false)
                    map['{}'] --;
                break;
            case ',':
                filter($match);
                break;
            case '"':
                map['"'] = !map['"'];
                if(map['[]'] === 1 && map['{}'] === 0)
                    arr.push($match);
                break;
            default:
                if(map['[]'] === 1 && map['{}'] === 0)
                {
                    if($match !== ' ')
                        arr.push($match);
                    else if(map['"'] === true)
                        arr.push($match);
                }
                break;
        }

        return $match;
    });
    console.log(arrMatch);
})('["学习",2022,"看电影",true,"打球", null,{"hobbyA":123},["nest"],"[",    "}",false]');

返回结果

['"学习"', '2022', '"看电影"', 'true', '"打球"', 'null', '"["', '"}"', 'false']

如果这是个考题,那考的应该是是基础能力,用状态机解决应该是一个很规范的答案,就是个基本的词法解析嘛,只需要:字符串,数字,保留字(true, null)

用正则的话不好覆盖边界情况

str = '["学习",2022,"看电影",true,"打球",null,{"hobbyA":123}]'
r = /[[,]("([^\"]+)"|(\d+)|null|true)/g
while(m = r.exec(str)) console.log(m[2]||m[1])

看到这种对正则熟悉度考量的不自觉的就写了下,你可以参考下
let str = '["学习",2022,"看电影",true,"打球",null,{"hobbyA":123}]';
str.match(/(?<=[|\,)(1+)(?=]|\,)/g)
image.png


  1. \:{}[]\,
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏