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

2020-07-04 23:09:04 +08:00
 supermoonie

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

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

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

3547 次点击
所在节点    JavaScript
45 条回复
alan0liang
2020-07-05 09:14:07 +08:00
略微有点偏题: https://alf.nu/RegexGolf
justgodlike1993
2020-07-05 10:25:42 +08:00
"[^"]*?"
no1xsyzy
2020-07-05 14:47:57 +08:00
@supermoonie #16 完美?
/(?<=name=").*?(?=")/g
,请?同后缀 lookbehind 竟然不合并…… 而且不需要匹配的部分不应该 (...) 而是 (?:...)
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
2020-07-05 15:10:07 +08:00
另外,根据上述 caniuse
你这个正则只有在 71% 左右的浏览器上可运行。
Safari 全灭。
supermoonie
2020-07-05 20:25:47 +08:00
@no1xsyzy 后来多的 \s+ 是我自己加上去做测试的,忘记去掉了。前端的兼容性问题真是让人脑壳疼,没想到一个正则,各家浏览器支持竟然不一样,感谢大佬科普!由于是项目初期,先保证在 Chrome 能正常使用,所以兼容性目前不是考虑的重点,后期会不停迭代进行优化。(想尽早出一个版本,一个人的精力有限😂)
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
2020-07-05 20:56:48 +08:00
@no1xsyzy 现在我能想到的最简单的正则就是 /"([^;]*)"/g 这个了,匹配到的结果再把双引号给 replace 掉。。。大佬有好的思路吗?
supermoonie
2020-07-05 21:00:01 +08:00
@jiejiss 个人项目,一开始只是想用正则试下,发现这个正则不是太好写,就来问问各位大佬,扩展下思路,学习了[抱拳]
supermoonie
2020-07-05 21:00:37 +08:00
@justgodlike1993 用的这个 /"([^;]*)"/g 正则,最后再把双引号 replace 掉
no1xsyzy
2020-07-05 22:41:15 +08:00
发现之前写完了没发(
@supermoonie #28 /"([^"]*)"/g 然后拿 group 1 。反正文件名带引号极少(因为 Windows 下不支持),有引号也应该转义的,而且因为是 web,转义是 % 的做法,所以排除引号很稳定。
@jiejiss #27 XML 是因为可递归所以不能用正则。
jiejiss
2020-07-05 23:16:02 +08:00
@no1xsyzy #31 可递归也不一定不能用正则的,现在很多语言的正则引擎支持很多 irregular 的 feature 比如 lookbehind 和引用,我甚至可以用正则匹配正整数域内全部 3/5/7 的倍数。甚至 perl 的正则都是图灵完备的了

关键其实在于正则有合适的使用场景,我希望的是楼主看完这篇回答能认识到正则不是万能的
supermoonie
2020-07-05 23:20:25 +08:00
@no1xsyzy
https://assets-1253328229.cos.ap-shanghai.myqcloud.com/assets/20200705231821.png
这点倒是提醒我了,文件名中带双引号,浏览器可能会转译,不过 Apache HttpClient 发出的请求却是 \" ,还是要处理下
supermoonie
2020-07-05 23:26:27 +08:00
@jiejiss 受教了,楼猪主要从事 Java 开发,所以对前端这块不是特别熟悉,现在已经能不用正则就不用正则了
no1xsyzy
2020-07-05 23:27:37 +08:00
@jiejiss #32 也是,重点在于不必拿正则做一切的观念,而不仅仅是具体某个问题是否适合。
不过,在当前主题下,我觉得没必要为了一行去搞个 parser,反复 split,相比之下单纯针对引号会更方便一点。
如果是大的物件的一部分,已经引入了 HTTP 相关内容还是 parser 比较好。
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
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
2020-07-05 23:45:47 +08:00
@no1xsyzy 大佬 666 啊,正则随手就来,协议链接也很有说服力,佩服佩服
supermoonie
2020-07-06 00:21:04 +08:00
@no1xsyzy 最终方案:

let _sub = function(str) {
return [...str.matchAll(/name="([^\s]+)"/g)].map(item => item[1]);
};
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"]

规则说明:匹配双引号里边的内容,开头双引号要求是“="”

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/687210

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX