regex - Golang替换任何和所有换行符
问题描述
通常,当我替换换行符时,我会跳转到正则表达式,就像在这个 PHP 中一样
preg_replace('/\R/u', "\n", $String);
因为我知道这是替换任何类型的 Unicode 换行符(无论是 \n、\r、\r\n 等)的一种非常持久的方法。
我也在 Go 中尝试过这样的事情,但我明白了
解析正则表达式时出错:无效的转义序列:
\R
在这条线上
msg = regexp.MustCompilePOSIX("\\R").ReplaceAllString(html.EscapeString(msg), "<br>\n")
我尝试(?:(?>\r\n)|\v)
从https://stackoverflow.com/a/4389171/728236使用,但看起来 Go 的正则表达式实现也不支持,恐慌invalid or unsupported Perl syntax: '(?>'
在 Go、Regex 中替换换行符的好、安全的方法是什么?
我在这里看到了这个答案Golang: Issues replace newlines in a string from a text file say to use \r?\n
,但我犹豫是否相信它会得到所有Unicode 换行符,主要是因为这个问题的答案列出了更多的换行符代码点\r?\n
涵盖的 3 个,
解决方案
虽然使用正则表达式通常会产生一个优雅而紧凑的解决方案,但它通常不是最快的。
对于必须用其他子字符串替换某些子字符串的任务,标准库以以下形式提供了一个非常有效的解决方案strings.Replacer
:
Replacer 用替换替换字符串列表。多个 goroutine 并发使用它是安全的。
您可以使用 来创建可重复使用的替换器strings.NewReplacer()
,在其中列出包含可替换部件及其替换的对。当您想要执行替换时,您只需调用Replacer.Replace()
.
这是它的样子:
const replacement = "<br>\n"
var replacer = strings.NewReplacer(
"\r\n", replacement,
"\r", replacement,
"\n", replacement,
"\v", replacement,
"\f", replacement,
"\u0085", replacement,
"\u2028", replacement,
"\u2029", replacement,
)
func replaceReplacer(s string) string {
return replacer.Replace(s)
}
以下是Wiktor 回答中的正则表达式解决方案的样子:
var re = regexp.MustCompile(`\r\n|[\r\n\v\f\x{0085}\x{2028}\x{2029}]`)
func replaceRegexp(s string) string {
return re.ReplaceAllString(s, "<br>\n")
}
实施实际上相当快。这是一个简单的基准,将其与上述预编译的正则表达式解决方案进行比较:
const input = "1st\nsecond\r\nthird\r4th\u0085fifth\u2028sixth"
func BenchmarkReplacer(b *testing.B) {
for i := 0; i < b.N; i++ {
replaceReplacer(input)
}
}
func BenchmarkRegexp(b *testing.B) {
for i := 0; i < b.N; i++ {
replaceRegexp(input)
}
}
以及基准测试结果:
BenchmarkReplacer-4 3000000 495 ns/op
BenchmarkRegexp-4 500000 2787 ns/op
对于我们的测试输入,速度快strings.Replacer
了5 倍以上。
还有另一个优势。在上面的示例中,我们将结果作为新string
值获得(在两种解决方案中)。这需要新的string
分配。如果我们需要将结果写入 an io.Writer
(例如,我们正在创建 HTTP 响应或将结果写入文件),我们可以避免创建 newstring
以防万一,strings.Replacer
因为它有一个方便的Replacer.WriteString()
方法,它接受io.Writer
并写入结果进入它而不分配和返回它作为一个string
. 与正则表达式解决方案相比,这进一步显着提高了性能增益。
推荐阅读
- c - 在 MikroC 中创建 250ms 延迟
- reactjs - 使用 Codemirror 突出显示语法不起作用
- python - 有没有办法将字符串转换为列表?
- node.js - 测试 api 获取时间线帖子错误。尽管所有其他路由测试都成功连接到数据库
- html - 状态更改后的 Bootstrap Dropdown 更新位置
- javascript - 如何在 ReactJS 中设置 Material UI 表的样式,以使表头和表体均匀分布?
- mysql - MySQL - 导出姓氏列表
- html - CSS:从 ID 中选择孙子锚
- flextable - Flextable 似乎与 multicol LaTex 包不兼容
- http-live-streaming - Winamp - HLS 收音机 (m3u8)