求个 js 正则,脑子最近进水,暂时想不出来 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
supermoonie
V2EX    Javascript

求个 js 正则,脑子最近进水,暂时想不出来

  •  
  •   supermoonie 2020-07-04 23:09:04 +08:00 4094 次点击
    这是一个创建于 1929 天前的主题,其中的信息可能已经有所发展或是发生改变。

    输入如下: Content-Disposition: form-data; name="test.png"; filename="test.jpg" 或 Content-Disposition: form-data; name="foo"

    输出: ['test.png', 'test.jpg'] 或 ['foo']

    哪位大佬指导下?[献花][献花][献花]

    45 条回复    2020-07-06 23:23:12 +08:00
    creanme
        1
    creanme  
       2020-07-04 23:18:38 +08:00 via Android
    手机回复的,也没测试,就当瞎写的。
    name=(".*\.png");filename=(".*\.jpg")

    用$1 与$2 输出
    mingl0280
        2
    mingl0280  
       2020-07-04 23:20:54 +08:00
    (\")(\S+)(\")取第二组。
    mingl0280
        3
    mingl0280  
       2020-07-04 23:21:31 +08:00
    https://regex101.com/
    这个网站可以直接测试正则,挺好用的。
    aheadin
        4
    aheadin  
       2020-07-04 23:25:27 +08:00   1
    function(str) {
    return [...str.matchAll(/name="([\w+.]+)"/g)].map(item => item[1])
    }
    supermoonie
        5
    supermoonie  
    OP
       2020-07-04 23:28:53 +08:00
    @mingl0280 /(?:")(\S+)(?:")/.exec('Content-Disposition: form-data; name="test.png"; filename="test.jpg"') 稍微改了下,返回的是 [""test.png"", "test.jpg"],第一个多了双引号。。。
    supermoonie
        6
    supermoonie  
    OP
       2020-07-04 23:33:06 +08:00
    @aheadin niubility,大佬能一个正则匹配出来吗?
    supermoonie
        7
    supermoonie  
    OP
       2020-07-04 23:34:02 +08:00
    @creanme 第二种情况满足不了
    ochatokori
        8
    ochatokori  
       2020-07-04 23:45:02 +08:00
    js 的正则最简单了,挖空填入(.*?)就好了
    ```Javascript
    text.match(/name="(.*?)"(.*?)filename="(.*?)"/)
    // 取数组的 1 和 3
    如果想第二种情况节 /name="(.*?)"/
    ```
    autoxbc
        9
    autoxbc  
       2020-07-04 23:45:50 +08:00   3
    正则就是圣杯,不管什么问题搞成正则就对了 <-- 害人不浅
    sedgwickz
        10
    sedgwickz  
       2020-07-04 23:47:06 +08:00   1
    'Content-Disposition: form-data; name="test.png"; filename="test.jpg" 或 Content-Disposition: form-data; name="foo"'.match(/(?<=(name\="|filename\=")).*?(?=")/g)
    supermoonie
        11
    supermoonie  
    OP
       2020-07-04 23:47:53 +08:00
    @ochatokori 分开写,我也会,我在尝试一个正则怎么给取出来,貌似有点难。。。
    lidlesseye11
        12
    lidlesseye11  
       2020-07-04 23:50:35 +08:00
    。。。你这个需求不就是取引号里的东西吗?
    supermoonie
        13
    supermoonie  
    OP
       2020-07-04 23:50:50 +08:00
    @sedgwickz niubility,大佬一出手就知有没有
    supermoonie
        14
    supermoonie  
    OP
       2020-07-04 23:53:44 +08:00
    @lidlesseye11 是的呢,目前只看到一位大佬写出来了,小弟反正是写不出来
    lidlesseye11
        15
    lidlesseye11  
       2020-07-05 00:11:43 +08:00
    @supermoonie
    那 split 比较简单粗暴吧。。
    function getName(str) {
    var arr = str.split("\"");
    var rtnArr = new Array();
    for(var i = 0;i < arr.length; i++) {
    if (i%2!=0) rtnArr.push(arr[i]);
    }
    return rtnArr;
    }
    supermoonie
        16
    supermoonie  
    OP
       2020-07-05 00:23:12 +08:00
    @lidlesseye11 你不觉得 /(?<=(name="|filename=")).*?(?=")/g 这个正则很完美吗?( emmm... 主要是项目是自己的,所以自己能看懂就行了,虽然我知道 split 更直接更易读,但是一旦有了想用正则去做,就会不死不休)
    mingl0280
        17
    mingl0280  
       2020-07-05 00:27:07 +08:00
    @supermoonie 正则匹配下来应该是个 iterator 啊,你在想啥
    ```
    var str = 'Content-Disposition: form-data; name="test.png"; filename="test.jpg"'
    var matches = str.matchAll(/(")(\S+)(")/g)
    for(const match of matches)
    {
    console.log(`${match[2]}`)
    }
    ```
    xiaoming1992
        18
    xiaoming1992  
       2020-07-05 00:29:31 +08:00
    const str = ""

    const reg = /(?<=name=\")(.+?)(?=\")/g

    let exec = reg.exec(str)

    const resultArray = []

    while (exec) {

    __resultArray.push(exec[0])

    __reg.exec(str)

    }
    supermoonie
        19
    supermoonie  
    OP
       2020-07-05 00:33:40 +08:00
    @mingl0280 想的是一行代码搞定,有就返回['test.png', 'test.jpg'] 或者 ['foo'] ,没有就返回 null,/(?<=(name="|filename=")).*?(?="\s+)/g 这个正则不是更香吗?
    supermoonie
        20
    supermoonie  
    OP
       2020-07-05 00:34:09 +08:00
    @xiaoming1992 谢了,前面有位大佬提供了 /(?<=(name="|filename=")).*?(?="\s+)/g
    alan0liang
        21
    alan0liang  
       2020-07-05 09:14:07 +08:00 via Android
    略微有点偏题: https://alf.nu/RegexGolf
    justgodlike1993
        22
    justgodlike1993  
       2020-07-05 10:25:42 +08:00
    "[^"]*?"
    no1xsyzy
        23
    no1xsyzy  
       2020-07-05 14:47:57 +08:00
    @supermoonie #16 完美?
    /(?<=name=").*?(?=")/g
    ,请?同后缀 lookbehind 竟然不合并…… 而且不需要匹配的部分不应该 (...) 而是 (?:...)
    no1xsyzy
        24
    no1xsyzy  
       2020-07-05 15:07:19 +08:00
    对了,/(?<=(name="|filename=")).*?(?="\s+)/g 有若干问题
    1. lookbehind 在 Firefox < 78 不可用(参考: https://caniuse.com/#feat=js-regexp-lookbehind ),这个主题让我发现我该更新了。更新到 78 就可用了;另外 #3 似乎会根据浏览器版本来改变 Javascript 下的效果(或者是因为就是用的浏览器实现)。
    2. (?="\s+) 严格要求 lookahead 是一个引号和至少一个空白符。而你的第一个输入中,test.png 后面是 "; 一个引号一个分号,也就不会被获取,应该改成 (?=") (我发现你过了十分钟后的回复多了 \s+ )
    3. 不要 capturing group 不需要的部分,应该用 non-capturing group 。
    4. 如果是 Perl 下面,lookbehind 要求宽度一致。name="|filename=" 宽度不一致。
    no1xsyzy
        25
    no1xsyzy  
       2020-07-05 15:10:07 +08:00
    另外,根据上述 caniuse
    你这个正则只有在 71% 左右的浏览器上可运行。
    Safari 全灭。
    supermoonie
        26
    supermoonie  
    OP
       2020-07-05 20:25:47 +08:00
    @no1xsyzy 后来多的 \s+ 是我自己加上去做测试的,忘记去掉了。前端的兼容性问题真是让人脑壳疼,没想到一个正则,各家浏览器支持竟然不一样,感谢大佬科普!由于是项目初期,先保证在 Chrome 能正常使用,所以兼容性目前不是考虑的重点,后期会不停迭代进行优化。(想尽早出一个版本,一个人的精力有限)
    jiejiss
        27
    jiejiss  
       2020-07-05 20:43:20 +08:00
    1. 请写 string parser,你这个需求用正则带来的心智负担更大
    2. 正则不是银弹,不是所有情况下都要用正则
    3. 想练手可以去 https://www.hackerrank.com/domains/regex,想进阶可以去 https://alf.nu/RegexGolf
    4. https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags
    supermoonie
        28
    supermoonie  
    OP
       2020-07-05 20:56:48 +08:00
    @no1xsyzy 现在我能想到的最简单的正则就是 /"([^;]*)"/g 这个了,匹配到的结果再把双引号给 replace 掉。。。大佬有好的思路吗?
    supermoonie
        29
    supermoonie  
    OP
       2020-07-05 21:00:01 +08:00
    @jiejiss 个人项目,一开始只是想用正则试下,发现这个正则不是太好写,就来问问各位大佬,扩展下思路,学习了[抱拳]
    supermoonie
        30
    supermoonie  
    OP
       2020-07-05 21:00:37 +08:00
    @justgodlike1993 用的这个 /"([^;]*)"/g 正则,最后再把双引号 replace 掉
    no1xsyzy
        31
    no1xsyzy  
       2020-07-05 22:41:15 +08:00
    发现之前写完了没发(
    @supermoonie #28 /"([^"]*)"/g 然后拿 group 1 。反正文件名带引号极少(因为 Windows 下不支持),有引号也应该转义的,而且因为是 web,转义是 % 的做法,所以排除引号很稳定。
    @jiejiss #27 XML 是因为可递归所以不能用正则。
    jiejiss
        32
    jiejiss  
       2020-07-05 23:16:02 +08:00
    @no1xsyzy #31 可递归也不一定不能用正则的,现在很多语言的正则引擎支持很多 irregular 的 feature 比如 lookbehind 和引用,我甚至可以用正则匹配正整数域内全部 3/5/7 的倍数。甚至 perl 的正则都是图灵完备的了

    关键其实在于正则有合适的使用场景,我希望的是楼主看完这篇回答能认识到正则不是万能的
    supermoonie
        33
    supermoonie  
    OP
       2020-07-05 23:20:25 +08:00
    @no1xsyzy
    https://assets-1253328229.cos.ap-shanghai.myqcloud.com/assets/20200705231821.png
    这点倒是提醒我了,文件名中带双引号,浏览器可能会转译,不过 Apache HttpClient 发出的请求却是 \" ,还是要处理下
    supermoonie
        34
    supermoonie  
    OP
       2020-07-05 23:26:27 +08:00
    @jiejiss 受教了,楼猪主要从事 Java 开发,所以对前端这块不是特别熟悉,现在已经能不用正则就不用正则了
    no1xsyzy
        35
    no1xsyzy  
       2020-07-05 23:27:37 +08:00
    @jiejiss #32 也是,重点在于不必拿正则做一切的观念,而不仅仅是具体某个问题是否适合。
    不过,在当前主题下,我觉得没必要为了一行去搞个 parser,反复 split,相比之下单纯针对引号会更方便一点。
    如果是大的物件的一部分,已经引入了 HTTP 相关内容还是 parser 比较好。
    no1xsyzy
        36
    no1xsyzy  
       2020-07-05 23:37:52 +08:00
    @supermoonie #33 我的错,拍脑袋了
    https://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1
    https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
    这里是一个 quoted-string,转义该用的就是 \"
    /"((?:\.|[^"\\])*)"/g
    supermoonie
        37
    supermoonie  
    OP
       2020-07-05 23:39:08 +08:00
    @no1xsyzy 其实需求是解析 HTTP 请求中 multipart 并展示,要把每一个 formdata 中的内容都解析出来,如果不用正则的话,就要先 split('\n') 分行,然后再每一行判断是否为 Content-Disposition,然后再解析,如果用正则的话,就可以根据 Content-Disposition 关键字一步到位,最终效果如图:
    https://assets-1253328229.cos.ap-shanghai.myqcloud.com/assets/20200705233841.png
    supermoonie
        38
    supermoonie  
    OP
       2020-07-05 23:45:47 +08:00
    @no1xsyzy 大佬 666 啊,正则随手就来,协议链接也很有说服力,佩服佩服
    supermoonie
        39
    supermoonie  
    OP
       2020-07-06 00:21:04 +08:00
    @no1xsyzy 最终方案:

    let _sub = function(str) {
    return [...str.matchAll(/name="([^\s]+)"/g)].map(item => item[1]);
    };
    MrUser
        40
    MrUser  
       2020-07-06 09:17:52 +08:00
    (?<==").*?(?=")/g

    JS 测试代码:

    'Content-Disposition: form-data; name="test.png"; filename="test.jpg" 或 Content-Disposition: form-data; name="foo"'.match(/(?<==").*?(?=")/g)

    // 输出:["test.png", "test.jpg", "foo"]

    规则说明:匹配双引号里边的内容,开头双引号要求是“="”
    MrUser
        41
    MrUser  
       2020-07-06 09:28:11 +08:00
    正则的前置断言各浏览器支持性确实不好,收回以上回复
    supermoonie
        42
    supermoonie  
    OP
       2020-07-06 09:41:59 +08:00
    @MrUser Safari 全军覆没。。。
    creanme
        43
    creanme  
       2020-07-06 21:19:27 +08:00
    我朋友写了个 /(?:(?:file)?name=)"([^"]+")/g,但是没法正常输出 groups,不知道为啥。string 的 match 在有 global 标志的情况下,不会输出 groups,只会输出匹配项。

    regex 的 exec 则 不管是 new Regexp('(?:(?:file)?name=)"([^"]+")','g')还是 new Regexp(/(?:(?:file)?name=)"([^"]+")/g)都没法匹配全局。
    creanme
        44
    creanme  
       2020-07-06 21:35:36 +08:00
    想通了,exec 有个 lastindex 标志位,所以不会一次输出全局的匹配。
    supermoonie
        45
    supermoonie  
    OP
       2020-07-06 23:23:12 +08:00
    @creanme 我已经抛弃 js 的正则了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2719 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 14:55 PVG 22:55 LAX 07:55 JFK 10:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86