2010-09-24 24 views
5

मेरे पास मेरी यूनिकोड लाइब्रेरी का एक हिस्सा है जो कच्चे यूनिकोड कोड बिंदुओं में यूटीएफ -16 को डीकोड करता है। हालांकि, यह उम्मीद के रूप में काम नहीं कर रहा है।यूटीएफ -16 डिकोडर अपेक्षित काम नहीं कर रहा है

typedef struct string { 
    unsigned long length; 
    unsigned *data; 
} string; 

string *upush(string *s, unsigned c) { 
    if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned)); 
    else   s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned)); 
    s->data[s->length - 1] = c; 
    return s; 
} 

typedef struct string16 { 
    unsigned long length; 
    unsigned short *data; 
} string16; 

string u16tou(string16 old) { 
    unsigned long i, cur = 0, need = 0; 
    string new; 
    new.length = 0; 
    for (i = 0; i < old.length; i++) 
     if (old.data[i] < 0xd800 || old.data[i] > 0xdfff) upush(&new, old.data[i]); 
     else 
      if (old.data[i] > 0xdbff && !need) { 
       cur = 0; continue; 
      } else if (old.data[i] < 0xdc00) { 
       need = 1; 
       cur = (old.data[i] & 0x3ff) << 10; 
       printf("cur 1: %lx\n", cur); 
      } else if (old.data[i] > 0xdbff) { 
       cur |= old.data[i] & 0x3ff; 
       upush(&new, cur); 
       printf("cur 2: %lx\n", cur); 
       cur = need = 0; 
      } 
    return new; 
} 

यह कैसे काम करता:

यहाँ कोड के प्रासंगिक भाग (UTF-8 और स्ट्रिंग परिवर्तन सामान को छोड़ते हुए) क्या है?

string एक ऐसी संरचना है जिसमें 32-बिट मान हैं, और string16 यूटीएफ -16 जैसे 16-बिट मानों के लिए है। सभी upush एक पूर्ण यूनिकोड कोड बिंदु string पर जोड़ता है, जो आवश्यकतानुसार स्मृति को पुन: आवंटित करता है।

u16tou वह हिस्सा है जिस पर मैं ध्यान केंद्रित कर रहा हूं। यह string16 के माध्यम से लूप करता है, सामान्य रूप से गैर सरोगेट मूल्यों को पारित करता है, और सरोगेट जोड़े को पूर्ण कोड बिंदुओं में परिवर्तित करता है। गलत जगहों को नजरअंदाज कर दिया जाता है।

एक जोड़ी में पहली सरोगेट में सबसे कम 10 बिट्स बाईं ओर 10 बिट्स स्थानांतरित हो गए हैं, जिसके परिणामस्वरूप यह अंतिम कोड बिंदु के उच्च 10 बिट बना रहा है। अन्य सरोगेट में फाइनल में सबसे कम 10 बिट जोड़े गए हैं, और फिर यह स्ट्रिंग में जोड़ा जाता है।

समस्या?

चलिए उच्चतम कोड बिंदु आज़माएं, क्या हम?

U+10FFFD, अंतिम मान्य यूनिकोड कोड बिंदु, यूटीएफ -16 में 0xDBFF 0xDFFD के रूप में एन्कोड किया गया है। आइए इसे डीकोड करने का प्रयास करें।

string16 b; 
b.length = 2; 
b.data = (unsigned short *) malloc(2 * sizeof(unsigned short)); 
b.data[0] = 0xdbff; 
b.data[1] = 0xdffd; 
string a = u16tou(b); 
puts(utoc(a)); 

का उपयोग utoc (नहीं दिखाया गया है, मैं जानता हूँ कि यह काम कर रहा (नीचे देखें)) समारोह इसे वापस एक UTF-8 मुद्रण के लिए char * में बदलने के लिए, मैं अपने टर्मिनल है कि मैं U+0FFFFD हो रही है में देख सकते हैं, नतीजतन U+10FFFD नहीं।

कैलकुलेटर

परिणाम एक ही है, गलत जवाब में gcalctool में मैन्युअल रूप से सभी रूपांतरण करने में। तो मेरा वाक्यविन्यास स्वयं गलत नहीं है, लेकिन एल्गोरिदम है। हालांकि एल्गोरिदम मेरे लिए सही लगता है, और फिर भी यह गलत जवाब में समाप्त हो रहा है।

मैं क्या गलत कर रहा हूं?

उत्तर

5

सरोगेट जोड़ी को डीकोड करते समय आपको 0x10000 पर जोड़ने की आवश्यकता है;

 
    1) If W1 < 0xD800 or W1 > 0xDFFF, the character value U is the value 
     of W1. Terminate. 

    2) Determine if W1 is between 0xD800 and 0xDBFF. If not, the sequence 
     is in error and no valid character can be obtained using W1. 
     Terminate. 

    3) If there is no W2 (that is, the sequence ends with W1), or if W2 
     is not between 0xDC00 and 0xDFFF, the sequence is in error. 
     Terminate. 

    4) Construct a 20-bit unsigned integer U', taking the 10 low-order 
     bits of W1 as its 10 high-order bits and the 10 low-order bits of 
     W2 as its 10 low-order bits. 

    5) Add 0x10000 to U' to obtain the character value U. Terminate. 

अर्थात्: rfc 2781 उद्धृत करने के लिए, कदम से वंचित हो रहे संख्या 5 है। एक ठीक अपने पहले पढ़ने के बाद एक अतिरिक्त पंक्ति जोड़ने के लिए होगा:

cur = (old.data[i] & 0x3ff) << 10; 
cur += 0x10000; 
+0

वाह, धन्यवाद! एक साधारण लापता कदम जोड़ा गया, और मेरा यूटीएफ -16 डिकोडर काम करता है! –

+0

कोई समस्या नहीं, यह सुनकर खुशी हुई कि यह अब काम करता है। मेरे टाइपो फिक्सिंग के लिए धन्यवाद :) – JosephH

0

आप एक 0x10000 की भरपाई गायब हो रहे हैं।

this WIKI page के अनुसार, UTF-16 के किराए की जोड़े इस तरह निर्माण कर रहे हैं:

UTF-16 गैर बीएमपी पात्रों (U + 10000 U + 10FFFF के माध्यम से) दो कोड इकाइयों का प्रयोग, के रूप में जाना का प्रतिनिधित्व करता है एक सरोगेट जोड़ी पहले 10000 को 20-बिट मान देने के लिए कोड बिंदु से घटाया गया है। इसे फिर दो 10-बिट मानों में विभाजित किया गया है, जिनमें से प्रत्येक को के रूप में दर्शाया गया है, जिसमें पहले सरोगेट में सबसे महत्वपूर्ण आधा स्थान दिया गया है।

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