我编写了这个短代码解析,它在O(N^2)中运行。有更好的方法来优化这个吗?
package shortcodes
import (
"regexp"
"strings"
)
var (
shortcodesRegex = regexp.MustCompile(`\[\S+(?:\s+[^="]+(|="[^"\]\s]+"))+\]`)
)
func Parse(content string) []map[string]string {
results := make([]map[string]string, 0)
indexes := shortcodesRegex.FindAllIndex([]byte(content), -1)
for _, matches := range indexes {
result := make(map[string]string)
shortcode := string(content[matches[0]+1 : matches[1]-1])
parts := strings.Fields(shortcode)
for i, part := range parts {
if i == 0 {
result["id"] = part
continue
}
pair := strings.Split(part, "=")
if len(pair) > 1 {
result[pair[0]] = pair[1][1 : len(pair[1])-1]
} else {
result[pair[0]] = ""
}
}
results = append(results, result)
}
return results
}这里是我编写的测试用例之一。
{
name: "basic",
args: args{`First shortcode is [fraction num="1" denom="2"] and the second is [square-root content="456"] which we will pass into a function which will return these IDs and all their values in a map`},
want: []map[string]string{
{
"id": "fraction",
"num": "1",
"denom": "2",
},
{
"id": "square-root",
"content": "456",
},
},
},发布于 2023-01-06 19:11:40
谢谢你的单元测试!它们是无价的;它们确实帮助我理解了你正在处理的问题。
我在读这个
\[\S+(?:\s+[^="]+(|="[^"\]\s]+"))+\]我对此并不满意,原因有几点。
应该有一个评论来说明我们寻求匹配的文本类型。( 短信参考是没有帮助的。)
匹配任务看起来相当简单,但是这个表达式相对不透明。我不认为这是一种向合作者传达技术想法的好方法。
?:非捕获组看起来很奇怪,并且有可能在regex引擎中触发过多的回溯,这可能就是您的二次运行时间的来源。
在代码的下面,我们发现字符串被解析了。
=-delimited拆分可以肯定的是,一只带着捕获群的大政王就能在一次突然袭击中挑出我们需要的东西?
如果有一个有效的短代码规范,请引用它的URL。正如所写的,这段代码愿意接受大量的$%^&*标点符号,我怀疑这不是预期的业务用例的一部分。
考虑使用看起来更像这样的regex:
^\[([\w-]+)(\s+\w+="\d+")+\]$或者使用细粒度捕获组:
\[([\w-]+)(\s+(\w+)="(\d+)")+\]如果[a b-c="7"]是有效输入,那么将\w+转换为[\w-]+。
字段和拆分逻辑足够普通,带有+/- 1索引偏移,可以去掉标点符号。逻辑与regex紧密绑定,正则表达式验证是否找到了正确的标点符号。我会更高兴地看到一些逻辑被推入正则表达式,将其保存在一个地方,并使维护人员更有可能正确地协调更改。使用细粒度捕获组似乎是实现这一目标的自然方法。
由于“过长的运行时间”一直是此代码在过去面临的挑战,请添加一个单元测试来解决这个问题,并验证没有回归。请添加代码,提供“非常长”的输入字符串进行分析,并记下经过的壁挂钟时间。
https://codereview.stackexchange.com/questions/282411
复制相似问题