2015-11-24 6 views
6

मैं इन 2 UTF-8 तार हैरूबी, समस्याओं UTF-8 वर्णों के साथ तार की तुलना

irb(main):039:0> puts "#{a} - #{b}" 
Nữ - Nữ 

संस्करण वह है जिसे मैंने डीबी में संग्रहीत किया है। बी संस्करण एक पोस्ट अनुरोध में ब्राउज़र से आ रहा है, मुझे नहीं पता कि ब्राउज़र यूटीएफ 8 अक्षरों का एक अलग संयोजन क्यों भेज रहा है, और यह हमेशा नहीं हो रहा है, मैं इस मुद्दे को पुन: पेश नहीं कर सकता मेरे देव पर्यावरण, यह उत्पादन में और कुल अनुरोधों के प्रतिशत में होता है।

मामला है कि मैं उन दोनों की तुलना करने की कोशिश, लेकिन वे false वापसी:

irb(main):022:0> c.force_encoding("UTF-8") == a.force_encoding("UTF-8") 
=> false 

एक और दिलचस्प तथ्य यह है:

irb(main):035:0> a == b 
=> false 

मैं एन्कोडिंग लिए मजबूर की तरह अलग अलग बातें की कोशिश की है :

irb(main):005:0> a.chars 
=> ["N", "ư", "̃"] 
irb(main):006:0> b.chars 
=> ["N", "ữ"] 

मैं इस तरह के तारों की तुलना कैसे कर सकता हूं?

+0

क्या आपको एक ही ब्राउज़र से ओ और बी मिलता है और ओएस? मुझे लगता है कि विशिष्ट ब्राउज़र/ओएस चरित्र प्रतिपादन मुद्दे की तरह लगता है। शायद आप स्पॉट प्रतिस्थापन तालिका को आजमा सकते हैं और फिर रिवर्स प्रतिस्थापन कर सकते हैं। – Cyrill

उत्तर

8

यह Unicode equivalence के साथ एक समस्या है। , द्वारा U + 0303 संयोजन टिल्ड बाद:

अपने स्ट्रिंग के a संस्करण चरित्र ư (सींग के साथ लैटिन छोटे अक्षर यू U + 01B0) के होते हैं। यह दूसरा चरित्र, जैसा कि नाम से पता चलता है combining character है, जो अंतिम ग्लाइफ का उत्पादन करने के लिए पिछले चरित्र के साथ प्रस्तुत किया जाता है।

स्ट्रिंग के b संस्करण चरित्र (U + 1EEF, सींग और टिल्ड के साथ लैटिन छोटे अक्षर यू) जो एक चरित्र है, और पिछले सम्मिश्रण के बराबर है, लेकिन एक अलग बाइट क्रम का उपयोग करता है का उपयोग करता है इसका प्रतिनिधित्व करने के लिए।

इन तारों की तुलना करने के लिए आपको सामान्यीकृत करने की आवश्यकता है, ताकि वे दोनों इन प्रकार के पात्रों के लिए एक ही बाइट अनुक्रम का उपयोग कर सकें। रुबी के वर्तमान संस्करणों में यह बनाया गया है (पहले संस्करणों में आपको किसी तृतीय पक्ष लाइब्रेरी का उपयोग करने की आवश्यकता है)।

तो वर्तमान में आप

a == b 

जो false है है, लेकिन आप true मिलना चाहिए अगर आप

a.unicode_normalize == b.unicode_normalize 

है।

यदि आप रूबी के पुराने संस्करण पर हैं, तो कुछ विकल्प हैं।रेल इसकी multibyte समर्थन के हिस्से के रूप में एक normalize विधि है, इसलिए यदि आप रेल का उपयोग कर रहे आप कर सकते हैं:

a.mb_chars.normalize == b.mb_chars.normalize 

या शायद कुछ की तरह:

ActiveSupport::Multibyte::Unicode.normalize(a) == ActiveSupport::Multibyte::Unicode.normalize(b) 

आप रेल का उपयोग नहीं कर रहे हैं, तो आप unicode_utils gem को देखो सकता है, और कुछ इस तरह करते हैं:

UnicodeUtils.nfkc(a) == UnicodeUtils.nfkc(b) 

(nfkc सामान्य रूप कहलाता है, यह DEFA रूप में ही है अन्य तकनीकों में अल्ट।)

यूनिकोड तारों को सामान्य करने के कई अलग-अलग तरीके हैं (यानी। चाहे आप विघटित या संयुक्त संस्करणों का उपयोग करें), और यह उदाहरण सिर्फ डिफ़ॉल्ट का उपयोग करता है। मैं आपको मतभेदों का शोध छोड़ दूंगा।

+0

मैं रूबी 2.0.0p247 का उपयोग कर रहा हूं, ऐसा लगता है कि यह मॉड्यूल एकीकृत नहीं है। किसी तीसरे भाग पुस्तकालय की सिफारिश की? मैंने पाया [यह एक] (https://github.com/rubysl/rubysl-unicode_normalize) लेकिन गीथूब पर कोई भी शुरुआत नहीं है और मुझे इसे स्थापित करने में समस्याएं भी हैं। – fguillen

+0

@fguillen मैंने कुछ सुझावों के साथ उत्तर द्वारा अद्यतन किया है। आपका प्रश्न रेल के साथ टैग किया गया है, इसलिए रेल के समर्थन का उपयोग शायद मुझे लगता है कि सबसे अच्छा समाधान होगा। – matt

+0

आप सही हैं मैंने रेल के आंतरिक यूनिकोड मॉड्यूल में नहीं सोचा था।मैंने आपके उत्तर में इस एस्केनारियो के लिए उदाहरण जोड़ा है, अगर सही नहीं है तो कृपया इसे सही करें। – fguillen

3

आप देख सकते हैं कि ये अलग-अलग वर्ण हैं। First और second। पहले मामले में, यह एक संशोधक "combining tilde" का उपयोग कर रहा है।

कोड बिंदु दृश्यों कि धर्मविधान समकक्ष के रूप में परिभाषित कर रहे हैं जब मुद्रित या प्रदर्शित एक ही उपस्थिति और अर्थ है मान लिया जाता:

विकिपीडिया इस पर एक अनुभाग है। उदाहरण के लिए, यू +0303 (लैटिन लोअरकेस "एन") के बाद कोड पॉइंट यू +0303 (संयोजन टिल्ड "◌") को यूनिकोड द्वारा परिभाषित किया गया है जो एकल कोड बिंदु यू +00 एफ 1 (लोअरकेस स्पैनिश वर्णमाला का अक्षर "ñ")। इसलिए, उन अनुक्रमों को उसी तरीके से प्रदर्शित किया जाना चाहिए, जैसे वर्णमाला नाम या खोज जैसे अनुप्रयोगों द्वारा उसी तरह व्यवहार किया जाना चाहिए, और एक-दूसरे के लिए प्रतिस्थापित किया जा सकता है।

और

मानक भी एक पाठ सामान्य प्रक्रिया है, यूनिकोड सामान्य कहा जाता है, कि पात्रों के बराबर दृश्यों की जगह तो यह है कि किसी भी दो ग्रंथों कि बराबर हैं कोड अंक की उसी क्रम से कम हो जाएगा परिभाषित करता है , सामान्य पाठ के सामान्यीकरण रूप या सामान्य रूप कहा जाता है।

ऐसा लगता है कि रूबी इस सामान्यीकरण का समर्थन करता है, लेकिन only as of Ruby 2.2:

http://ruby-doc.org/stdlib-2.2.0/libdoc/unicode_normalize/rdoc/String.html

a = "N\u01b0\u0303".unicode_normalize 
b = "N\u1eef".unicode_normalize 

a == b # true 

वैकल्पिक रूप से, अगर आप पर रूबी का उपयोग कर रहे हैं, वहाँ सामान्य के लिए एक built-in method प्रतीत होता है।

संबंधित मुद्दे