通常,当我替换换行符时,我会跳到Regexp,就像在这个PHP中一样
preg_replace('/\R/u', "\n", $String);
因为我知道这是替换任何种类的Unicode换行符(例如\ n,\ r,\ r \ n等)的一种非常持久的方式
我也在Go语言中尝试类似的操作,但是我得到
错误解析正则表达式:无效的转义序列:
\R
在此行
msg = regexp.MustCompilePOSIX("\\R").ReplaceAllString(html.EscapeString(msg), "<br>\n")
我尝试使用https://stackoverflow.com/a/4389171/728236中的(?:(?>\r\n)|\v)
,但看起来Go的正则表达式实现也不支持,invalid or unsupported Perl syntax: '(?>'
恐慌
在Go和Regex中替换换行符的一种好而安全的方法是什么?
我在这里Golang: Issues replacing newlines in a string from a text file看到了这个答案,说要使用\r?\n
,但是我不敢相信它将获得 all Unicode换行符,主要是因为这个问题答案列出了比\r?\n
涵盖的3个更多的换行代码点,
答案 0 :(得分:3)
您可以将\R
模式“解码”为
U+000DU+000A|[U+000AU+000BU+000CU+000DU+0085U+2028U+2029]
请参阅Java regex docs来解释\R
的简写:
Linebreak matcher \R Any Unicode linebreak sequence, is equivalent to \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
在Go中,您可以使用以下内容:
func removeLBR(text string) string {
re := regexp.MustCompile(`\x{000D}\x{000A}|[\x{000A}\x{000B}\x{000C}\x{000D}\x{0085}\x{2028}\x{2029}]`)
return re.ReplaceAllString(text, ``)
}
这里是Go demo。
某些Unicode代码可以用Go regexp支持的正则表达式转义序列代替:
re := regexp.MustCompile(`\r\n|[\r\n\v\f\x{0085}\x{2028}\x{2029}]`)
答案 1 :(得分:3)
虽然使用regexp通常会产生一种优雅而紧凑的解决方案,但它通常不是最快的。
对于必须将某些子字符串替换为其他子字符串的任务,标准库以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's answer中的正则表达式解决方案如下所示:
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")
}
实现实际上非常快。这是一个简单的基准,将其与上述预编译的regexp解决方案进行比较:
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
分配。如果需要将结果写入io.Writer
(例如,我们正在创建HTTP响应或将结果写入文件),则可以避免在出现{{的情况下,不必创建新的string
1}},因为它有一个方便的Replacer.WriteString()
方法,该方法接受一个strings.Replacer
并将结果写入其中,而无需以io.Writer
的形式分配和返回。与正则表达式解决方案相比,这可以进一步显着提高性能。