首页 \ 问答 \ Rails:尽管使用UTF8编码序列化哈希的困境(Rails: encoding woes with serialized hashes despite UTF8)

Rails:尽管使用UTF8编码序列化哈希的困境(Rails: encoding woes with serialized hashes despite UTF8)

我刚刚从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"

为了将这个字符串转换为红宝石哈希,我使用YAML.load反序列化它:

broken_hash = YAML.load(broken)

这会返回一个包含乱码的内容:

{"checkbox"=>"1", "choice"=>"Round Paper Clips  ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}

乱码的东西应该是UTF8编码的中文。 broken_hash['info'].encoding告诉我,ruby认为这是#<Encoding:UTF-8> 。 我不同意。

有趣的是,所有其他没有序列化的字符串看起来不错,但是。 在同一个记录中,不同的字段包含看起来恰到好处的中文字符 - 在rails控制台,psql控制台和浏览器中。 每一个字符串---不管是序列化的散列还是普通的字符串---由于更新看起来都很好,所以保存到数据库中。


尽管ruby声称这已经是UTF-8,我试图将可能出错的编码(如GB2312或ANSI)中的乱码文本转换为UTF-8,当然我失败了。 这是我使用的代码:

require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])

这个失败是因为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(...)将字符串转换为红宝石哈希时,事情才会分崩离析。 也许我应该在输入YAML.load之前处理原始字符串。 只是让我想知道为什么这样...


有趣! 这很可能是由于YAML引擎“心灵”在1.9.3中默认使用的。 我使用YAML::ENGINE.yamler = 'syck'切换到“syck”引擎,并且正确解析了断开的字符串。


I've just updated from ruby 1.9.2 to ruby 1.9.3p0 (2011-10-30 revision 33570). My rails application uses postgresql as its database backend. The system locale is UTF8, as is the database encoding. The default encoding of the rails application is also UTF8. I have Chinese users who input Chinese characters as well as English characters. The strings are stored as UTF8 encoded strings.

Rails version: 3.0.9

Since the update some of the existing Chinese strings in the database are no longer displayed correctly. This does not affect all strings, but only those that are part of a serialized hash. All other strings that are stored as plain strings still appear to be correct.


Example:

This is a serialized hash that is stored as a UTF8 string in the database:

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"

In order to convert this string to a ruby hash, I deserialize it with YAML.load:

broken_hash = YAML.load(broken)

This returns a hash with garbled contents:

{"checkbox"=>"1", "choice"=>"Round Paper Clips  ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}

The garbled stuff is supposed to be UTF8-encoded Chinese. broken_hash['info'].encoding tells me that ruby thinks this is #<Encoding:UTF-8>. I disagree.

Interestingly, all other strings that were not serialized before look fine, however. In the same record a different field contains Chinese characters that look just right---in the rails console, the psql console, and the browser. Every string---no matter if serialized hash or plain string---saved to the database since the update looks fine, too.


I tried to convert the garbled text from a possible wrong encoding (like GB2312 or ANSI) to UTF-8 despite ruby's claim that this was already UTF-8 and of course I failed. This is the code I used:

require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])

This fails because ruby doesn't know what to do with illegal sequences in the string.

I really just want to run a script to fix all the old, presumably broken serialized hash strings and be done with it. Is there a way to convert these broken strings to something resembling Chinese again?


I just played with the encoded UTF-8 string in the raw string (called "broken" in the above example). This is the Chinese string that is encoded in the serialized string:

chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"

I noticed that it is easy to convert this to a real UTF-8 encoded string by unescaping it (removing the escape backslashes).

chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"

This returns a proper UTF-8-encoded Chinese string: "(回形针)\r\n"

The thing falls apart only when I use YAML.load(...) to convert the string to a ruby hash. Maybe I should process the raw string before it is fed to YAML.load. Just makes me wonder why this is so...


Interesting! This is likely due to the YAML engine "psych" that's used by default now in 1.9.3. I switched to the "syck" engine with YAML::ENGINE.yamler = 'syck' and the broken strings are correctly parsed.


原文:https://stackoverflow.com/questions/8558101
更新时间:2023-05-29 06:05

最满意答案

您将需要支付每次调用的固定附加成本才能使用Java源代码中的OpenGL。 Android为这些调用提供了Java语言包装器。 例如,如果调用glDrawArrays ,则调用在android_opengl_GLES20.cpp中定义的GLES20.java中声明的本机方法。 你可以从代码中看到它只是以最小的开销转发呼叫。

在文件中徘徊,你可以看到其他调用执行额外的检查,因此稍微昂贵。

至于不可避免的成本,底线是使用Java源代码进行大量GLES调用的价格高于本地源代码。 (在使用systrace查看Android Breakout的性能时,我注意到驱动程序中有很多CPU开销,因为我正在执行大量冗余状态更新。从本机代码执行此操作的代价会更低,但是做零工作的成本低于做更少工作的成本。)

更深层次的问题与您是否需要如此不同地编写代码(例如为了避免分配)无法获得相同级别的性能有关。 你必须使用直接的ByteBuffer对象而不是简单的数组,这可能需要更多的管理。 但是除了目前计算密集型本机和Android上的Java代码之间的速度差异之外,我不知道任何从根本上阻止了严格Java实现的良好性能。


You're going to be paying a fixed additional cost per call to use OpenGL from Java source code. Android provides Java-language wrappers around the calls. For example, if you call glDrawArrays, you're calling a native method declared in GLES20.java, which is defined in android_opengl_GLES20.cpp. You can see from the code that it's just forwarding the call with minimal overhead.

Nosing around in the file, you can see other calls that perform additional checks and hence are slightly more expensive.

The bottom line as far as unavoidable costs goes is that the price of making lots of GLES calls is higher with Java source than native source. (While looking at the performance of Android Breakout with systrace I noticed that there was a lot of CPU overhead in the driver because I was doing a lot of redundant state updates. The cost of doing so from native code would have been lower, but the cost of doing zero work is less than the cost of doing less work.)

The deeper question has to do with whether you need to write your code so differently (e.g. to avoid allocations) that you simply can't get the same level of performance. You do have to work with direct ByteBuffer objects rather than simple arrays, which may require a bit more management on your side. But aside from the current speed differences between compute-intensive native and Java code on Android, I'm not aware of anything that fundamentally prevents good performance from strictly-Java implementations.

相关问答

更多
  • 我已经创建了一个关于如何将用Java完成的UI与执行所有OpenGL渲染的本机NDK代码相结合的示例。 可以不使用GLSurfaceView和JNI调用来渲染每个帧,就像在NDK示例中完成的那样。 请参阅https://github.com/tsaarni/android-native-egl-example上的代码 I've created an example on how to combine UI done in Java with native NDK code that does all the ...
  • 您将需要支付每次调用的固定附加成本才能使用Java源代码中的OpenGL。 Android为这些调用提供了Java语言包装器。 例如,如果调用glDrawArrays ,则调用在android_opengl_GLES20.cpp中定义的GLES20.java中声明的本机方法。 你可以从代码中看到它只是以最小的开销转发呼叫。 在文件中徘徊,你可以看到其他调用执行额外的检查,因此稍微昂贵。 至于不可避免的成本,底线是使用Java源代码进行大量GLES调用的价格高于本地源代码。 (在使用systrace查看And ...
  • 如果你有一个适用于Android的C ++ 11编译器,你可以使用几个框架(我写过Infectorpp ),但还有其他框架可用。 您应该注意到,由于缺乏反射 ,DI在C ++中非常有限,因此您应该做出一些妥协,因为您在RoboGuice中所做的一切都不可能。 通过快速搜索,似乎可以在Android上使用C ++ 11。 我没有Android设备但仍然不需要模拟它,但是如果你有任何反馈它会很好 (这里的私人消息或谷歌代码上的支持票就足够了),这个库只是标题所以没有特别的构建东西它是必需的,除了在你的编译器上启 ...
  • 要从另一个线程调用OpenGL ES函数,您必须在两个线程之间创建共享的OpenGL ES上下文。 有一个更简单的解决方案 - 将事件发送到拥有OpenGL ES上下文的线程,以便在第二个线程中加载纹理后立即更新纹理。 To call OpenGL ES functions from another thread you have to create a shared OpenGL ES context between 2 threads. There is an easier solution - sen ...
  • 这不是一个正确的生命周期,但它已经接近了。 每当GL表面变得完全模糊时,其EGL上下文将被破坏,并且当发生这种情况时,将释放通过OpenGL调用分配的任何资源。 因此,除非您的应用程序在运行时需要主动管理(例如,在内存中缓存太多纹理等),否则无需手动释放这些资源。 请注意,这仅适用于OpenGL通过OpenGL调用分配的资源和内存。 您像往常一样需要释放在OpenGL之外分配的任何缓冲区。 That's not quite the right lifecycle, but it's close. Any t ...
  • 重要的是要注意,你所指的文档是在ndk实际上能够处理诸如活动之类的东西之前。 因此,那时您需要做的是使用sdk创建一个Android应用程序,并且至少需要为活动生命周期事件创建一个java包装类,它调用本机代码。 此外,如果您想要声音或与用户进行其他交互,您通常也必须使用sdk。 然而,现在看起来你可能会将NDK用于整个应用程序(虽然我还没有尝试过),但是如果你想使用标准的UI元素,比如选择游戏文件的列表,我仍然会使用SDK。 It's important to note that the document ...
  • NDK用于将C / C ++ / asm代码编译为二进制文件。 你可以用NDK做很多事情,比如编译可执行文件,静态预编译器......但最终,在Android应用程序的上下文中,你可以获得一个或多个.so文件 (共享对象库)。 从Java,你可以加载这样的.so文件和映射在它们内部实现的函数。 Android应用程序项目仅包含C / C ++代码(请参阅NDK的本机活动示例),但这仍然是一个原理:.so文件在ART或Dalvik上下文中加载。 Android应用程序中的任何内容都是在Dalvik虚拟机或AR ...
  • 例如:从1到1,000,000的总和自然数。 代码如下: unsigned int sum = 0; for(int i = 1; i <= 1000000; ++i) { sum += i; } 如果上面的代码是由java编码的,那么花费的时间可能大约是200ms。 但是在jni中用c编码时,时间只需要约30毫秒。 你可以试试。 for example: sum natural number from 1 to 1,000,000. the code is as follow: unsigned ...
  • 简短的回答是C / C ++代码中不包含任何反射信息,C / C ++具有Java编译器不执行的内联函数,宏和展开循环(与C / C ++编译器一样多) 。 也可以如此广泛地优化C / C ++,因为没有对应用程序自身功能的引用,所以您可以做的就是反编译为汇编。 (虽然可以找到对系统功能的参考。) The short answer is that the C/C++ code does not contain any reflective information in it and C/C++ has in ...
  • 在Android上,您可以使用Java做任何事情,您可以使用NDK,因为您可以简单地使用JNI 。 如果从NDK对Java进行多次调用,则应考虑创建一个JNI包装类,它将调用机制减少到更少的行。 虽然我没有尝试过,但Android文档中没有任何内容表明GLSurfaceView不能与特定类型的窗口布局一起使用。 On Android, anything you can do with Java, you can do with the NDK, because you can simply use JNI. ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。