我刚刚从ruby 1.9.2更新到ruby 1.9.3p0(2011-10-30修订版33570).我的rails应用程序使用postgresql作为其数据库后端.系统区域设置是UTF8,数据库编码也是如此.rails应用程序的默认编码也是UTF8.我有中国用户输入汉字和英文字符.字符串存储为UTF8编码的字符串.
Rails版本:3.0.9
由于更新,数据库中的一些现有中文字符串不再正确显示.这不会影响所有字符串,只会影响序列化哈希的一部分.存储为纯字符串的所有其他字符串仍然看起来是正确的.
例:
这是一个序列化哈希,在数据库中存储为UTF8字符串:
broken = "--- !map:ActiveSupport::HashWithIndifferentAccess \ncheckbox: \"1\"\nchoice: \"Round Paper Clips \\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"\ninfo: \"10\\xE7\\x9B\\x92\"\n"
Run Code Online (Sandbox Code Playgroud)
为了将此字符串转换为ruby哈希,我使用YAML.load
以下命令对其进行反序列化:
broken_hash = YAML.load(broken)
Run Code Online (Sandbox Code Playgroud)
这将返回带有乱码内容的哈希:
{"checkbox"=>"1", "choice"=>"Round Paper Clips ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}
Run Code Online (Sandbox Code Playgroud)
乱码的东西应该是UTF8编码的中文.broken_hash['info'].encoding
告诉我,红宝石认为这是#<Encoding:UTF-8>
.我不同意.
有趣的是,之前没有序列化的所有其他字符串看起来都很好.在同一条记录中,不同的字段包含看起来正确的中文字符---在rails控制台,psql控制台和浏览器中.每个字符串---无论是序列化哈希还是普通字符串---都保存到数据库中,因为更新看起来也很好.
我试图将乱码文本从可能错误的编码(如GB2312或ANSI)转换为UTF-8,尽管ruby声称这已经是UTF-8了,当然我失败了.这是我使用的代码:
require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])
Run Code Online (Sandbox Code Playgroud)
这失败了,因为ruby不知道如何处理字符串中的非法序列.
我真的只想运行一个脚本来修复所有旧的,可能是破坏的序列化哈希字符串并完成它.有没有办法将这些断弦转换成类似中文的东西?
我只是在原始字符串中使用编码的UTF-8字符串(在上面的示例中称为"已损坏").这是在序列化字符串中编码的中文字符串:
chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"
我注意到通过取消它(删除转义反斜杠)很容易将其转换为真正的UTF-8编码字符串.
chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"
这将返回一个正确的UTF-8编码的中文字符串: "?????\r\n"
只有当我使用YAML.load(...)
将字符串转换为ruby哈希时,事情才会崩溃.也许我应该在它被送到之前处理原始字符串YAML.load
.只是让我想知道为什么会这样......
有趣!这可能是由于YAML引擎"心理"现在在1.9.3中默认使用.我切换到"syck"引擎,YAML::ENGINE.yamler = 'syck'
并正确解析损坏的字符串.
我正在使用Codec.Crypto.RSA来加密随机字符串,该字符串通过base64表示中的套接字传递给外部进程.外部进程(使用openssl进行解密的ruby程序)有时无法解密消息.
为了调试这个,我在haskell中设置了一个简单的脚本,用于加密和解密固定的消息,所有这些都没有base64编码/解码.令我困惑的是,这个非常简单的程序在几次迭代后导致失败.解密的密文不等于原始消息,尽管消息包含在解密中(在一些不可打印的字符之后).
这是代码:
import Crypto.Random
import qualified Codec.Crypto.RSA as RSA
import qualified Data.ByteString.Lazy.Char8 as L
m :: L.ByteString
m = L.pack "11111222223333344444555556666600"
main = do
gen <- newGenIO :: IO SystemRandom
let (pub, priv, _) = RSA.generateKeyPair gen 1024
doStuff pub priv
doStuff pub priv = do
gen <- newGenIO :: IO SystemRandom
let (e,_) = RSA.encrypt' RSA.UsePKCS1_v1_5 gen pub m
let d = RSA.decrypt' RSA.UsePKCS1_v1_5 priv e
if (m == d)
then do
putStrLn "SUCCESS"
doStuff pub priv
else …
Run Code Online (Sandbox Code Playgroud)