您的字符串是 UTF-8。
我知道,因为您的解决方法是用字节 (195, 164) 替换字节 (97, 204, 136)。
您要替换的第一个字节 97 (0x61) 是 UTF-8 字符 a。后两个字节 204 和 136 (0xCC 0x88) 是 UTF-8 字符 U+0308、combining diaeresis:̈ 的字节。这两个字符组合成ä。
您期望的字节是 195 和 164 (0xC3 0xA4),它们加起来是 U+00E4 或 Latin small letter "a" with diaeresis。
两者都是 UTF-8。一个打印ä,另一个打印ä。这是Unicode equivalence 的示例。
换句话说:
str1 = "a\xCC\x88"
puts str1 # => ä
p str1.bytes # => [97, 204, 136]
p str1.encoding # => #<Encoding:UTF-8>
str2 = "\xC3\xA4"
puts str2 # => ä
p str2.bytes # => [195, 164]
p str2.encoding # => #<Encoding:UTF-8>
幸运的是,我们有 Unicode normalization 来帮助解决这个问题。这是一个大的话题,但 TL;DR 的不足之处在于 Unicode 联盟已经规定了标准化上述字符串的标准方法,即如何将 str1 转换为 str2。
很遗憾,由于您没有提供任何详细信息,因此无法说出最适合您的解决方案。您的数据库可能具有内置的规范化功能,但我不知道您使用的是什么数据库,所以我不能说。既然您确实提到了 Ruby,我可以为您指出 String#unicode_normalize 方法,该方法是在 Ruby 2.2 的 Ruby 标准库中引入的:
str1 = "a\xCC\x88"
str2 = "\xC3\xA4"
p str1 == str2 # => false
str1_normalized = str1.unicode_normalize
p str1_normalized == str2
# => true
p str1_normalized.bytes == str2.bytes
# => true
如果您没有 Ruby 2.2+,那么……升级。但如果由于某种原因无法升级,您可以使用ActiveSupport::Multibyte::Unicode.normalize,如果您使用的是 Rails,这会特别方便,或者Unicode gem。
还有一件事
你不需要这样做,因为上面是在 Ruby 中进行 Unicode 规范化的正确方法,但是更简单的方法:
"WinterIDäSchwiiz".bytes.join(",").gsub("97,204,136","195,164").split(",").collect{|s| s.to_i }.pack('C*').force_encoding('utf-8')
...应该是这样的:
"WinterIDäSchwiiz".gsub("a\xCC\x88", "\xC3\xA4")
任何时候你在 Ruby 中看到类似 join(",")...split(",") 的东西,这几乎肯定是错误的解决方案。