输入如下: Content-Disposition: form-data; name="test.png"; filename="test.jpg" 或 Content-Disposition: form-data; name="foo"
输出: ['test.png', 'test.jpg'] 或 ['foo']
哪位大佬指导下?[献花][献花][献花]
1
creanme 2020-07-04 23:18:38 +08:00 via Android
手机回复的,也没测试,就当瞎写的。
name=(".*\.png");filename=(".*\.jpg") 用$1 与$2 输出 |
2
mingl0280 2020-07-04 23:20:54 +08:00
(\")(\S+)(\")取第二组。
|
3
mingl0280 2020-07-04 23:21:31 +08:00
https://regex101.com/
这个网站可以直接测试正则,挺好用的。 |
4
aheadin 2020-07-04 23:25:27 +08:00 1
function(str) {
return [...str.matchAll(/name="([\w+.]+)"/g)].map(item => item[1]) } |
5
supermoonie OP @mingl0280 /(?:")(\S+)(?:")/.exec('Content-Disposition: form-data; name="test.png"; filename="test.jpg"') 稍微改了下,返回的是 [""test.png"", "test.jpg"],第一个多了双引号。。。
|
6
supermoonie OP @aheadin niubility,大佬能一个正则匹配出来吗?
|
7
supermoonie OP @creanme 第二种情况满足不了😂
|
8
ochatokori 2020-07-04 23:45:02 +08:00
js 的正则最简单了,挖空填入(.*?)就好了
```javascript text.match(/name="(.*?)"(.*?)filename="(.*?)"/) // 取数组的 1 和 3 如果想第二种情况节 /name="(.*?)"/ ``` |
9
autoxbc 2020-07-04 23:45:50 +08:00 3
正则就是圣杯,不管什么问题搞成正则就对了 <-- 害人不浅
|
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)
|
11
supermoonie OP @ochatokori 分开写,我也会😂,我在尝试一个正则怎么给取出来,貌似有点难。。。
|
12
lidlesseye11 2020-07-04 23:50:35 +08:00
。。。你这个需求不就是取引号里的东西吗?
|
13
supermoonie OP @sedgwickz niubility,大佬一出手就知有没有
|
14
supermoonie OP @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; } |
16
supermoonie OP @lidlesseye11 你不觉得 /(?<=(name="|filename=")).*?(?=")/g 这个正则很完美吗?( emmm... 主要是项目是自己的,所以自己能看懂就行了,虽然我知道 split 更直接更易读,但是一旦有了想用正则去做,就会不死不休😂)
|
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]}`) } ``` |
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) } |
19
supermoonie OP @mingl0280 想的是一行代码搞定,有就返回['test.png', 'test.jpg'] 或者 ['foo'] ,没有就返回 null,/(?<=(name="|filename=")).*?(?="\s+)/g 这个正则不是更香吗?
|
20
supermoonie OP @xiaoming1992 谢了,前面有位大佬提供了 /(?<=(name="|filename=")).*?(?="\s+)/g
|
21
alan0liang 2020-07-05 09:14:07 +08:00 via Android
略微有点偏题: https://alf.nu/RegexGolf
|
22
justgodlike1993 2020-07-05 10:25:42 +08:00
"[^"]*?"
|
23
no1xsyzy 2020-07-05 14:47:57 +08:00
|
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=" 宽度不一致。 |
25
no1xsyzy 2020-07-05 15:10:07 +08:00
另外,根据上述 caniuse
你这个正则只有在 71% 左右的浏览器上可运行。 Safari 全灭。 |
26
supermoonie OP @no1xsyzy 后来多的 \s+ 是我自己加上去做测试的,忘记去掉了。前端的兼容性问题真是让人脑壳疼,没想到一个正则,各家浏览器支持竟然不一样,感谢大佬科普!由于是项目初期,先保证在 Chrome 能正常使用,所以兼容性目前不是考虑的重点,后期会不停迭代进行优化。(想尽早出一个版本,一个人的精力有限😂)
|
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 |
28
supermoonie OP @no1xsyzy 现在我能想到的最简单的正则就是 /"([^;]*)"/g 这个了,匹配到的结果再把双引号给 replace 掉。。。大佬有好的思路吗?
|
29
supermoonie OP @jiejiss 个人项目,一开始只是想用正则试下,发现这个正则不是太好写,就来问问各位大佬,扩展下思路,学习了[抱拳]
|
30
supermoonie OP @justgodlike1993 用的这个 /"([^;]*)"/g 正则,最后再把双引号 replace 掉
|
31
no1xsyzy 2020-07-05 22:41:15 +08:00
发现之前写完了没发(
@supermoonie #28 /"([^"]*)"/g 然后拿 group 1 。反正文件名带引号极少(因为 Windows 下不支持),有引号也应该转义的,而且因为是 web,转义是 % 的做法,所以排除引号很稳定。 @jiejiss #27 XML 是因为可递归所以不能用正则。 |
32
jiejiss 2020-07-05 23:16:02 +08:00
@no1xsyzy #31 可递归也不一定不能用正则的,现在很多语言的正则引擎支持很多 irregular 的 feature 比如 lookbehind 和引用,我甚至可以用正则匹配正整数域内全部 3/5/7 的倍数。甚至 perl 的正则都是图灵完备的了
关键其实在于正则有合适的使用场景,我希望的是楼主看完这篇回答能认识到正则不是万能的 |
33
supermoonie OP @no1xsyzy
https://assets-1253328229.cos.ap-shanghai.myqcloud.com/assets/20200705231821.png 这点倒是提醒我了,文件名中带双引号,浏览器可能会转译,不过 Apache HttpClient 发出的请求却是 \" ,还是要处理下 |
34
supermoonie OP @jiejiss 受教了,楼猪主要从事 Java 开发,所以对前端这块不是特别熟悉,现在已经能不用正则就不用正则了
|
35
no1xsyzy 2020-07-05 23:27:37 +08:00
@jiejiss #32 也是,重点在于不必拿正则做一切的观念,而不仅仅是具体某个问题是否适合。
不过,在当前主题下,我觉得没必要为了一行去搞个 parser,反复 split,相比之下单纯针对引号会更方便一点。 如果是大的物件的一部分,已经引入了 HTTP 相关内容还是 parser 比较好。 |
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 |
37
supermoonie OP @no1xsyzy 其实需求是解析 HTTP 请求中 multipart 并展示,要把每一个 formdata 中的内容都解析出来,如果不用正则的话,就要先 split('\n') 分行,然后再每一行判断是否为 Content-Disposition,然后再解析,如果用正则的话,就可以根据 Content-Disposition 关键字一步到位,最终效果如图:
https://assets-1253328229.cos.ap-shanghai.myqcloud.com/assets/20200705233841.png |
38
supermoonie OP @no1xsyzy 大佬 666 啊,正则随手就来,协议链接也很有说服力,佩服佩服
|
39
supermoonie OP @no1xsyzy 最终方案:
let _sub = function(str) { return [...str.matchAll(/name="([^\s]+)"/g)].map(item => item[1]); }; |
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"] 规则说明:匹配双引号里边的内容,开头双引号要求是“="” |
41
MrUser 2020-07-06 09:28:11 +08:00
正则的前置断言各浏览器支持性确实不好,收回以上回复
|
42
supermoonie OP @MrUser Safari 全军覆没。。。
|
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)都没法匹配全局。 |
44
creanme 2020-07-06 21:35:36 +08:00
想通了,exec 有个 lastindex 标志位,所以不会一次输出全局的匹配。
|
45
supermoonie OP @creanme 我已经抛弃 js 的正则了😂
|