Golang截断具有特殊字符的字符串而不会破坏数据

时间:2017-09-26 00:04:47

标签: go utf-8 special-characters

我正在尝试编写一个函数来截断golang中带有特殊字符的字符串。一个例子如下:

"H㐀〾▓朗퐭텟şüöžåйкл¤"

但是我根据允许的字符数量在中间切割它。这会导致数据损坏。

结果如

H㐀〾▓朗퐭텟şüöžå�...

不应该在那里。我们如何检测这些特殊字符并根据这些字符的长度进行拆分?

package main

import (
    "fmt"
    "regexp"
)

var reNameBlacklist = regexp.MustCompile(`(&|>|<|\/|:|\n|\r)*`)
var maxFileNameLength = 30

// SanitizeName sanitizes user names in an email
func SanitizeName(name string, limit int) string {

    result := name
    reNameBlacklist.ReplaceAllString(result, "")
    if len(result) > limit {
        result = result[:limit] + "..."
    }
    return result
}



func main() {
  str := "H㐀〾▓朗퐭텟şüöžåйкл¤"
    fmt.Println(str)

    strsan := SanitizeName(str, maxFileNameLength)
    fmt.Println(strsan)

}

3 个答案:

答案 0 :(得分:8)

切片字符串将它们视为基础字节数组; slice运算符对字节索引进行操作,而不是符文(每个符号可以是多个字节)。但是,range超过一个字符串迭代符文 - 但返回的索引是字节。这样可以非常直接地完成您正在寻找的内容(full playground example here):

func SanitizeName(name string, limit int) string {
    reNameBlacklist.ReplaceAllString(name, "")
    result := name
    chars := 0
    for i := range name {
        if chars >= limit {
            result = name[:i]
            break
        }
        chars++
    }
    return result
}

更详细地解释了这一点on the Go blog

答案 1 :(得分:2)

您的数据损坏的原因是因为某些字符使用多个字节并且您正在拆分它们。为了避免这种情况,Go的类型rune表示UTF-8字符。您可以将字符串转换为[]rune,如下所示:

func SanitizeName(name string, limit int) string{   
    reNameBlacklist.ReplaceAllString(name, "")
    result := []rune(name)
    // Remove the special chars here
    return string(result[:limit])
}

这应该只保留第一个限制 UTF-8字符。

答案 2 :(得分:0)

另一个选项是 utf8string 包:

package main
import "golang.org/x/exp/utf8string"

func main() {
   s := utf8string.NewString("?????")
   t := s.Slice(0, 2)
   println(t == "??")
}

https://pkg.go.dev/golang.org/x/exp/utf8string