string - 清理坏的 UTF-8 字符串
问题描述
由于格式错误的用户数据,我的gRPC
服务未能发送请求。原来 HR 用户数据有一个错误的UTF-8
字符串,gRPC
无法对其进行编码。我将坏字段缩小到这个字符串:
"Gr\351gory Smith" // Gr�gory Smith (this is coming from an LDAP source)
所以我想要一种方法来清理这些输入,如果它们包含错误的UTF-8
编码。
在标准包中没有看到任何明显的消毒功能unicode/utf8
,这是我第一次天真的尝试:
func naïveSanitizer(in string) (out string) {
for _, rune := range in {
out += string(rune)
}
return
}
输出:
Before: Valid UTF-8? false Name: 'Gr�gory Smith' Byte-Count: 13
After: Valid UTF-8? true Name: 'Gr�gory Smith' Byte-Count: 15
UTF-8
有没有更好或更标准的方法来从坏字符串中挽救尽可能多的有效数据?
我在这里暂停的原因是因为在迭代字符串并且遇到错误(第 3 个)字符时,utf8.ValidRune(rune)
返回true
: https: //play.golang.org/p/_FZzeTRLVls
所以我的后续问题是,迭代一个字符串 - 一次一个符文 - 符文值是否始终有效?即使底层的源字符串编码格式错误?
编辑:
澄清一下,这些数据来自 LDAP 源:500K 用户记录。在这 50 万条记录中,只有 15 条(十五条),即约 0.03%返回uf8.ValidString(...)
.false
正如@kostix 和@peterSO 所指出的,如果从另一种编码(例如Latin-1)转换为UTF-8,这些值可能是有效的。将此理论应用于这些异常样本:
https://play.golang.org/p/9BA7W7qQcV3
Name: "Jean-Fran\u00e7ois Smith" : (good UTF-8) : : Jean-François Smith
Name: "Gr\xe9gory" : (bad UTF-8) : Latin-1-Fix: Grégory
Name: "Fr\xe9d\xe9ric" : (bad UTF-8) : Latin-1-Fix: Frédéric
Name: "Fern\xe1ndez" : (bad UTF-8) : Latin-1-Fix: Fernández
Name: "Gra\xf1a" : (bad UTF-8) : Latin-1-Fix: Graña
Name: "Mu\xf1oz" : (bad UTF-8) : Latin-1-Fix: Muñoz
Name: "P\xe9rez" : (bad UTF-8) : Latin-1-Fix: Pérez
Name: "Garc\xeda" : (bad UTF-8) : Latin-1-Fix: García
Name: "Gro\xdfmann" : (bad UTF-8) : Latin-1-Fix: Großmann
Name: "Ure\xf1a" : (bad UTF-8) : Latin-1-Fix: Ureña
Name: "Iba\xf1ez" : (bad UTF-8) : Latin-1-Fix: Ibañez
Name: "Nu\xf1ez" : (bad UTF-8) : Latin-1-Fix: Nuñez
Name: "Ba\xd1on" : (bad UTF-8) : Latin-1-Fix: BaÑon
Name: "Gonz\xe1lez" : (bad UTF-8) : Latin-1-Fix: González
Name: "Garc\xeda" : (bad UTF-8) : Latin-1-Fix: García
Name: "Guti\xe9rrez" : (bad UTF-8) : Latin-1-Fix: Gutiérrez
Name: "D\xedaz" : (bad UTF-8) : Latin-1-Fix: Díaz
Name: "Encarnaci\xf3n" : (bad UTF-8) : Latin-1-Fix: Encarnación
解决方案
Go 1.13 引入了strings.ToValidUTF8()
,所以sanitizer()
应该是:
func sanitize(s string) string {
return strings.ToValidUTF8(s, "")
}
我什至认为它不应该有它自己的功能。在Go Playground上尝试一下。
如果您的输入恰好是字节切片,您可以使用类似的bytes.ToValidUTF8()
功能。
另请注意,如果您不只是想从输入中丢弃一些数据而没有跟踪,则可以在调用时使用任何替换字符(或多个字符)strings.ToValidUTF8()
,例如:
return strings.ToValidUTF8(in, "❗")
在Go Playground上试试这个。
推荐阅读
- mysql - 查找小于等于0但没有重复记录的记录
- r - 如何转换 R 代码以使特定列位于与其他列相关联的一行中?
- html - 获取 API 休息和过去到 Json + Html
- react-native - 错误:h.playTouchSound 不是函数?
- excel - 需要处理删除表中的行的异常情况
- reactjs - react - × TypeError: users.map 不是函数
- language-agnostic - 抽象数据类型是否仅限于数据结构?
- php - 如何在“WordPress Google Click to Deploy”上启用 SOAP
- html - 图像 src 不渲染 instagram 的图像
- python - 熊猫替换功能不适用于字符串系列