V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Jwyt
V2EX  ›  正则表达式

求教下疑惑了很久的一个正则

  •  
  •   Jwyt · 2021-06-30 16:01:07 +08:00 · 1224 次点击
    这是一个创建于 1024 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如一个类似 json 的字符串
    "date":["2020-06-03","2020-06-05","2020-06-12","2020-06-19","2020-06-24","2020-07-03","2020-07-10","2020-07-17","2020-07-24","2020-07-31","2020-08-07","2020-08-14","2020-08-21","2020-08-28","2020-09-04","2020-09-11","2020-09-18","2020-09-25","2020-10-09","2020-10-16","2020-10-23","2020-10-30","2020-11-06","2020-11-13","2020-11-20","2020-11-27","2020-12-04","2020-12-11"],"data":[0,-0.33,-0.04,-0.33,-0.32,-0.18,-0.99,-0.84,-0.33,-0.57,-0.65,-0.52,-0.65,-0.95,-1.08,-1.01,-0.96,-0.89,-0.97,-0.98,-0.71,-0.6,-0.47,-0.63,-0.79,-0.59,-0.41,-0.33],"ret":[0,0,0.02,1.33,1.27,1.53,1.33,1.54,1.8,1.96,2.16,2.3,2.34,2.31,2.38,2.41,1.89,2.01,2.18,2.29,2.39,2.49,2.6,2.6,2.51,2.54,2.71,2.86]

    求教能否只用一条正则获取"ret": 里面的所有数值(多行)?
    结果:
    0
    0
    0.02
    1.33
    ....
    14 条回复    2021-06-30 18:21:22 +08:00
    keepeye
        1
    keepeye  
       2021-06-30 16:15:09 +08:00
    可能匹配不出来,只能把 ret 取出来 split
    IgniteWhite
        2
    IgniteWhite  
       2021-06-30 16:19:40 +08:00
    同不会写。我的感觉是这种 pattern 是非正则的,如果让我去做我会把 ret 里的内容用正则提出来,再用一个 csv parser 或者一个正则包里的 split 函数得到数值
    woodensail
        3
    woodensail  
       2021-06-30 16:23:00 +08:00
    一次正则理论上可以,不过要用断言判断当前数字后面没有 ret 出现,而且老实说通用性不强,所以我倾向于两次正则
    str.match(/ret[^[]+\[([^[]+)\]/)[1].match(/[\d\.]+/g)
    InDom
        4
    InDom  
       2021-06-30 16:27:20 +08:00
    正则不是万能的,另外不要写过于复杂的正则,这玩意写不好性能非常差!!!

    非要凑在一个里面实现,可能代码量少了,但执行时间会 toooooooooooo looooooooooog
    woodensail
        5
    woodensail  
       2021-06-30 16:29:32 +08:00
    更正一下,第一个正则里面匹配数字内容的部分应该改成排除右括号。虽然左括号也没错,但是确实右括号更合理。

    str.match(/ret[^[]+\[([^\]]+)/)[1].match(/[\d\.]+/g)
    keepeye
        6
    keepeye  
       2021-06-30 16:33:28 +08:00
    @woodensail 能一次匹配出结果吗 我想学习下
    imn1
        7
    imn1  
       2021-06-30 16:35:31 +08:00
    这个正则不难,问题的点不在这里,而是正则输出的是 str 类型,而 json 表示的是 int 类型,除非只是显示用途,不然还有一个转换步骤,那还不如直接 json 解
    莫不是一个 GB 级的 json ?
    woodensail
        8
    woodensail  
       2021-06-30 16:40:03 +08:00
    @keepeye str.match(/[\d\.]+(?!.*ret)/g)
    用零宽断言,匹配数字同时要求数字后面不会出现 ret 字符.
    缺点 1: 性能相比两次法差了很多。
    缺点 2: 如果字段顺序变了或者 ret 字段后面又追加了其他字段就不行了。
    lujjjh
        9
    lujjjh  
       2021-06-30 16:53:44 +08:00   ❤️ 1
    str.match(/(?<="ret":\[[^\]]*)[^,\]]+/g)

    抛开 lookbehind assertion 的兼容性问题,这么写也是不够准确的,要看你这个“类似 json 的字符串”具体格式是什么样
    keepeye
        10
    keepeye  
       2021-06-30 17:05:27 +08:00
    @woodensail 是的,实际情况可不能保证说 ret 是最后一个字段,map 是没有顺序的
    Jwyt
        11
    Jwyt  
    OP
       2021-06-30 17:06:46 +08:00
    @keepeye @IgniteWhite @InDom
    谢谢,看来还是上代码
    @imn1 也不是- - 就是一个老爬虫框架,使用有些限制
    Jwyt
        12
    Jwyt  
    OP
       2021-06-30 17:09:37 +08:00
    @woodensail 是的,ret 后面的内容我没复制,不过 ret 里的内容确实匹配到了
    Jwyt
        13
    Jwyt  
    OP
       2021-06-30 17:20:57 +08:00
    @lujjjh 感谢 确实可以。不过就像你说的,刚好这个老框架(php)不兼容模糊长度的断言。。看来还是得用其他办法了
    wjfz
        14
    wjfz  
       2021-06-30 18:21:22 +08:00   ❤️ 1
    给两头各加一个花括号,然后 json decode
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   956 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:47 · PVG 03:47 · LAX 12:47 · JFK 15:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.