- 发生时间:2022-07-11
- 问题描述:
- 运行某个 JS 仓库的测试用例,有 2 个失败。报错信息为
JSON.parse error: TypeError: Cannot read property '0' of null。
- 运行某个 JS 仓库的测试用例,有 2 个失败。报错信息为
- 问题类别:软件测试
- 原因分析:
- 阅读源代码,定位到报错代码为
const content = frame.content.toString().match(/\{.*?\}/g)[0]。 - 根据报错信息,可以推断 match 的结果为 null,导致索引其第一个元素失败。
frame.content的值为读取文件tasks/test/assets/auto_detect_result.json得到的字节流。- 分析至此,可以怀疑这里正则表达式的写法了。
/\{.*?\}/g匹配的是以一对花括号为边界、中间为任意字符的字符串, 按道理应该能匹配 json 字符串才对,为啥匹配不到东西呢? - 查阅 MDN 「Regular_Expressions」 下面的 「Character classes」文档 发现, 点号无法匹配换行符! 而待匹配的字符串中含有很多换行符!这就是匹配不上的原因。
- 另外,这里正则表达式中对问号的使用也是有风险的,应该删掉更合适。
因为问号代表「一旦匹配到就停止」(详见下文「JavaScript 正则表达式中的问号」),
比如对于字符串
{{}},会匹配到{{}就停止,而我们期望匹配到{{}}。
- 阅读源代码,定位到报错代码为
- 解决方案:在 stack overflow 找到两种解决方案:
- 方案一:使用
[^]代替点号。这种方案只适用于 JavaScript。 - 方案二:使用
[\s\S]代替点号。这种方案可移植性更好,很多语言都适用,比如 JavaScript、Python 和 Golang。
- 方案一:使用
- 实施结果:采用方案一后,运行 ft4_tasks 的测试用例,全部 pass。
- 经验总结:
- 大多数编程语言的正则表达式中的点号默认不会匹配换行符。经过实测,JavaScript、Python 和 Golang 都这样。
- 要想匹配包括换行符在内的任意字符,可以使用
[\s\S]。经过实测,JavaScript、Python 和 Golang 都支持这样匹配。
各门编程语言的正则表达式的点号
JavaScript
以下是 MDN 文档 对 JavaScript 正则表达式里面的点号 . 的描述:
.Has one of the following meanings:- Matches any single character except line terminators:
\n, \r, \u2028 or \u2029. For example,/.y/matches “my” and “ay”, but not “yes”, in “yes make my day”. - Inside a character class, the dot loses its special meaning and matches a literal dot.
- Note that the m multiline flag doesn’t change the dot behavior.
So to match a pattern across multiple lines, the character class
[^]can be used — it will match any character including newlines. - ES2018 added the s “dotAll” flag, which allows the dot to also match line terminators.
- Matches any single character except line terminators:
Python
以下是 Python 官方文档 对 Python 正则表达式里面的点号 . 的描述:
- (Dot.) In the default mode, this matches any character except a newline.
- If the DOTALL flag has been specified, this matches any character including a newline.
Golang
以下是 Go 官方文档 对 Golang 正则表达式里面的点号 . 的描述:
- any character, possibly including newline (flag s=true)
JavaScript 正则表达式的问号
以下是 MDN 文档 对 JavaScript 正则表达式里面的问号 ? 的描述:
-
By default quantifiers like
*and+are “greedy”, meaning that they try to match as much of the string as possible. -
The
?character after the quantifier makes the quantifier “non-greedy”: meaning that it will stop as soon as it finds a match. -
For example, given a string like
some <foo> <bar> new </bar> </foo> thing:/<.*>/will match<foo> <bar> new </bar> </foo>/<.*?>/will match<foo>