के बावजूद सीरियलाइज्ड हैश के साथ एन्कोडिंग की समस्याएं मैंने अभी रुबी 1.9.2 से रूबी 1.9.3p0 (2011-10-30 संशोधन 33570) से अपडेट किया है। मेरे रेल एप्लिकेशन postgresql का उपयोग डेटाबेस बैकएंड के रूप में करता है। सिस्टम लोकेल यूटीएफ 8 है, जैसा डाटाबेस एन्कोडिंग है। रेल आवेदन के डिफ़ॉल्ट एन्कोडिंग भी यूटीएफ 8 है। मेरे पास चीनी उपयोगकर्ता हैं जो चीनी वर्णों के साथ-साथ अंग्रेजी वर्णों को इनपुट करते हैं। तारों को यूटीएफ 8 एन्कोडेड तारों के रूप में संग्रहीत किया जाता है।रेल: यूटीएफ 8
रेल संस्करण: 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
के साथ deserialize:
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
मुझे बताता है कि रूबी सोचता है कि यह #<Encoding:UTF-8>
है। मैं असहमत हूं।
दिलचस्प बात यह है कि, अन्य सभी तार जो ठीक दिखने से पहले क्रमबद्ध नहीं थे, हालांकि। उसी रिकॉर्ड में एक अलग फ़ील्ड में चीनी वर्ण होते हैं जो ठीक दिखते हैं --- रेल कंसोल, psql कंसोल और ब्राउज़र में। प्रत्येक स्ट्रिंग --- कोई फर्क नहीं पड़ता कि धारावाहिक हैश या सादा स्ट्रिंग --- डेटाबेस में सहेजा गया है क्योंकि अद्यतन ठीक दिखता है।
मैं रूबी के दावे कि यह पहले से ही था UTF-8 और निश्चित रूप से मैं में विफल रहा है के बावजूद UTF-8 में एक संभव गलत एन्कोडिंग (जीबी 2312 या एएनएसआई) की तरह से विकृत पाठ परिवर्तित करने के लिए कोशिश की।
require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])
यह विफल रहता है क्योंकि गहरे लाल रंग का क्या स्ट्रिंग में अवैध दृश्यों से कोई लेना देना नहीं जानता है: यह कोड मैं प्रयोग किया जाता है।
मैं वास्तव में बस सभी पुरानी, संभावित रूप से टूटी धारावाहिक हैश तारों को ठीक करने के लिए एक स्क्रिप्ट चलाने के लिए चाहता हूं और इसके साथ किया जाना चाहिए। क्या इन टूटे तारों को फिर से चीनी जैसा दिखने का कोई तरीका है?
मैं सिर्फ कच्चे स्ट्रिंग में एन्कोडेड UTF-8 स्ट्रिंग के साथ खेला जाता है (जिसे "टूटा" ऊपर के उदाहरण में)।
chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"
मैंने देखा है कि यह न छोड़ने (भागने बैकस्लैश को हटाने) द्वारा एक वास्तविक UTF-8 एन्कोडेड स्ट्रिंग में बदलने के लिए आसान है: यह चीनी स्ट्रिंग है जो धारावाहिक स्ट्रिंग में एन्कोड किया गया है है।"(回形针)\r\n"
बात अलग केवल जब मैं YAML.load(...)
का प्रयोग कर एक गहरे लाल रंग का हैश को स्ट्रिंग परिवर्तित करने के लिए आते हैं:
chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"
यह एक उचित UTF-8 एन्कोड चीनी स्ट्रिंग देता है। शायद इसे YAML.load
पर खिलाया जाने से पहले कच्ची स्ट्रिंग को संसाधित करना चाहिए। बस मुझे आश्चर्य है कि ऐसा क्यों है ...
दिलचस्प! यह संभवतः वाईएएमएल इंजन "मनोविज्ञान" के कारण होता है जिसका उपयोग डिफ़ॉल्ट रूप से 1.9.3 में किया जाता है। मैंने YAML::ENGINE.yamler = 'syck'
के साथ "सिक" इंजन पर स्विच किया और टूटे तारों को सही ढंग से पार्स किया गया।
धारावाहिक हैश के लिए कॉलम प्रकार क्या है? –
@muistooshort: कॉलम प्रकार 'text' है। – rekado
क्या होता है यदि आप कॉलम को 'बाइनरी' में बदलते हैं? इसे स्ट्रिंग को "8 बिट ASCII" (यानी कच्चे बाइट्स) के रूप में प्राप्त करना चाहिए और शायद वह 'YAML.load' को आकार में लाएगा। एक त्वरित परीक्षण के रूप में आप 'YAML.load (टूटा हुआ) 'से पहले' broken.force_encoding ('बाइनरी')' 'कर सकते हैं। –