为了账号安全,请及时绑定邮箱和手机立即绑定

Golang 替换所有换行符

Golang 替换所有换行符

Go
阿波罗的战车 2023-04-17 15:17:39
通常,当我替换换行符时,我会跳转到正则表达式,就像在这个 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 replacing newlines in a string from a text file saying to use \r?\n,但我犹豫是否相信它会得到所有Unicode 换行符,主要是因为这个问题的答案列出了比覆盖的3个\r?\n,
查看完整描述

2 回答

?
大话西游666

TA贡献1817条经验 获得超14个赞

虽然使用 regexp 通常会产生一个优雅而紧凑的解决方案,但它通常不是最快的。

对于必须用其他子字符串替换某些子字符串的任务,标准库以以下形式提供了一个非常有效的解决方案strings.Replacer

Replacer 用替换项替换字符串列表。多个 goroutines 并发使用是安全的。

您可以使用创建可重复使用的替换器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

对于我们的测试输入,速度提高了5 倍strings.Replacer以上。

还有另一个优点。在上面的示例中,我们将结果作为新string值获取(在两种解决方案中)。这需要一个新的string分配。如果我们需要将结果写入一个io.Writer(例如,我们正在创建一个 HTTP 响应或将结果写入一个文件),我们可以避免必须创建新的,string因为strings.Replacer它有一个方便的Replacer.WriteString()方法,它接受一个io.Writer并写入result into 它而不分配并将其作为 a 返回string。与正则表达式解决方案相比,这进一步显着提高了性能增益。


查看完整回答
反对 回复 2023-04-17
?
心有法竹

TA贡献1866条经验 获得超5个赞

您可以将模式“解码”\R为


U+000DU+000A|[U+000AU+000BU+000CU+000DU+0085U+2028U+2029]

请参阅解释速记的Java 正则表达式文档\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 演示。


一些 Unicode 代码可以用Go regexp支持的正则表达式转义序列替换:


re := regexp.MustCompile(`\r\n|[\r\n\v\f\x{0085}\x{2028}\x{2029}]`)


查看完整回答
反对 回复 2023-04-17
  • 2 回答
  • 0 关注
  • 253 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信