2012-07-02 19 views
7

मेरे पास स्ट्रिंग है जो यूटीएफ -8 एन्कोडेड वर्ण प्रदर्शित करती है, और मैं इसे वापस यूनिकोड में परिवर्तित करना चाहता हूं।यूटीएफ -8 स्ट्रिंग को यूनिकोड में कैसे परिवर्तित करें?

public static string DecodeFromUtf8(this string utf8String) 
{ 
    // read the string as UTF-8 bytes. 
    byte[] encodedBytes = Encoding.UTF8.GetBytes(utf8String); 

    // convert them into unicode bytes. 
    byte[] unicodeBytes = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, encodedBytes); 

    // builds the converted string. 
    return Encoding.Unicode.GetString(encodedBytes); 
} 

मैं शब्द "déjà" साथ खेल रहा हूँ:

अभी के लिए, मेरी कार्यान्वयन निम्नलिखित है। मैंने इसे online tool के माध्यम से यूटीएफ -8 में परिवर्तित कर दिया है, और इसलिए मैंने स्ट्रिंग "déjÃ" के साथ अपनी विधि का परीक्षण करना शुरू कर दिया।

दुर्भाग्यवश, इस कार्यान्वयन के साथ स्ट्रिंग बस वही बना हुआ है।

मैं कहाँ गलत हूँ?

+12

यह एक यूटीएफ 8 स्ट्रिंग नहीं है। यह एक दूषित स्ट्रिंग है जिसे गलत एन्कोडिंग का उपयोग करके बाइट्स से बुरी तरह से परिवर्तित किया गया है। – spender

+24

यूटीएफ -8 * * यूनिकोड है। –

+2

स्रोत स्ट्रिंग अमान्य यूटीएफ -8 है। – alexn

उत्तर

11

तो मुद्दा यह है कि यूटीएफ -8 कोड इकाई मानों को सी # string में 16-बिट कोड इकाइयों के अनुक्रम के रूप में संग्रहीत किया गया है। आपको बस यह सत्यापित करने की आवश्यकता है कि प्रत्येक कोड इकाई बाइट की सीमा के भीतर है, उन मानों को बाइट्स में कॉपी करें, और फिर नए यूटीएफ -8 बाइट अनुक्रम को यूटीएफ -16 में परिवर्तित करें।

public static string DecodeFromUtf8(this string utf8String) 
{ 
    // copy the string as UTF-8 bytes. 
    byte[] utf8Bytes = new byte[utf8String.Length]; 
    for (int i=0;i<utf8String.Length;++i) { 
     //Debug.Assert(0 <= utf8String[i] && utf8String[i] <= 255, "the char must be in byte's range"); 
     utf8Bytes[i] = (byte)utf8String[i]; 
    } 

    return Encoding.UTF8.GetString(utf8Bytes,0,utf8Bytes.Length); 
} 

DecodeFromUtf8("d\u00C3\u00A9j\u00C3\u00A0"); // déjà 

यह आसान है, हालांकि मूल कारण ढूंढना सबसे अच्छा होगा; वह स्थान जहां कोई यूटीएफ -8 कोड इकाइयों को 16 बिट कोड इकाइयों में कॉपी कर रहा है। संभावित अपराधी किसी को गलत एन्कोडिंग का उपयोग कर बाइट्स को सी # string में परिवर्तित कर रहा है। जैसे Encoding.Default.GetString(utf8Bytes, 0, utf8Bytes.Length)


वैकल्पिक रूप से, क्या आप वाकई गलत एन्कोडिंग जो स्ट्रिंग निर्माण करने के लिए इस्तेमाल किया गया था पता है, और कहा कि गलत एन्कोडिंग बदलने पर प्रभावित नहीं (आमतौर पर ऐसा करता है, तो गलत एन्कोडिंग एक एकल बाइट एन्कोडिंग है) था रहे हैं, तो आप बस मूल UTF-8 डेटा प्राप्त करने के प्रतिलोम एन्कोडिंग कदम कर सकते हैं, और फिर आप UTF-8 बाइट्स से सही रूपांतरण कर सकते हैं:

public static string UndoEncodingMistake(string mangledString, Encoding mistake, Encoding correction) 
{ 
    // the inverse of `mistake.GetString(originalBytes);` 
    byte[] originalBytes = mistake.GetBytes(mangledString); 
    return correction.GetString(originalBytes); 
} 

UndoEncodingMistake("d\u00C3\u00A9j\u00C3\u00A0", Encoding(1252), Encoding.UTF8); 
+0

धन्यवाद barnes53 यह वास्तव में मेरे प्रश्न का उत्तर देता है क्योंकि यह परिणाम मुझे उम्मीद करता है। आप यह जान सकते हैं कि मेरा भ्रमित प्रश्न से मेरा क्या मतलब था। – remio

8

मैं स्ट्रिंग कि UTF-8 एन्कोडेड वर्ण

वहाँ .NET में ऐसी कोई बात नहीं है प्रदर्शित होती है। स्ट्रिंग क्लास केवल यूटीएफ -16 एन्कोडिंग में तारों को स्टोर कर सकता है। एक यूटीएफ -8 एन्कोडेड स्ट्रिंग केवल बाइट [] के रूप में मौजूद हो सकती है। एक स्ट्रिंग में बाइट्स को स्टोर करने का प्रयास करना एक अच्छा अंत नहीं होगा; यूटीएफ -8 बाइट मानों का उपयोग करता है जिनके पास वैध यूनिकोड कोडपॉइंट नहीं है। स्ट्रिंग सामान्य होने पर सामग्री नष्ट हो जाएगी। इसलिए जब आपका DecodeFromUtf8() चलना शुरू हो जाता है तब तक स्ट्रिंग को पुनर्प्राप्त करने में बहुत देर हो चुकी है।

केवल बाइट [] के साथ यूटीएफ -8 एन्कोडेड टेक्स्ट को संभाल लें। और इसे बदलने के लिए UTF8Encoding.GetString() का उपयोग करें।

+0

का एक तरीका है आपने उस भ्रम की ओर इशारा किया जिसे मैं टालना चाहता था। मेरी स्ट्रिंग एक यूनिकोड स्ट्रिंग है, अच्छी तरह से एक .Net स्ट्रिंग है, जिसे डीबगर 'dà © jÃ'' के रूप में प्रदर्शित करता है। इसलिए, मेरा लक्ष्य एक और (.Net) स्ट्रिंग प्राप्त करना है जिसे 'डीजे' के रूप में प्रदर्शित किया जाएगा (उदाहरण के लिए डीबगर में)। – remio

+1

आप उत्तर का बिंदु खो रहे हैं, * हर * संभावित utf-8 एन्कोडेड स्ट्रिंग के लिए यह काम ठीक से करने का कोई तरीका नहीं है। कि आप इसे डीए © जेए के लिए काम कर सकते हैं केवल संयोग है। कि आप पहले से ही इस समस्या के साथ परेशानी हो रही है एक संकेत होना चाहिए, आखिरी Ã के बाद एक अतिरिक्त जगह है। एक विशेष, एक गैर-ब्रेकिंग स्पेस, कोड पॉइंट यू + 00 ए 0। जो दुर्घटना से वैध यूनिकोड कोड बिंदु होता है। –

+0

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

2

क्या आपके पास एक string गलत तरीके से दूसरे से डीकोड हो रहा है एन्कोडिंग, संभावित code page 1252, जो यूएस विंडोज डिफ़ॉल्ट है। कोई अन्य हानि मानते हुए, रिवर्स कैसे करें। आपकी स्ट्रिंग के अंत में non-breaking space (U + 00A0) तुरंत दिखाई देने वाला एक नुकसान प्रदर्शित नहीं होता है। बेशक डेटा स्रोत को पहले स्थान पर सही ढंग से पढ़ना बेहतर होगा, लेकिन शायद डेटा स्रोत को शुरू करने के लिए गलत तरीके से संग्रहीत किया गया था।

using System; 
using System.Text; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     string junk = "déjÃ\xa0"; // Bad Unicode string 

     // Turn string back to bytes using the original, incorrect encoding. 
     byte[] bytes = Encoding.GetEncoding(1252).GetBytes(junk); 

     // Use the correct encoding this time to convert back to a string. 
     string good = Encoding.UTF8.GetString(bytes); 
     Console.WriteLine(good); 
    } 
} 

परिणाम:

déjà 
9

आप एक UTF-8 स्ट्रिंग है, जहां हर बाइट सही है है ('o' -> [195, 0], [150, 0]), आप -> [195, 0

public static string Utf8ToUtf16(string utf8String) 
{ 
    /*************************************************************** 
    * Every .NET string will store text with the UTF-16 encoding, * 
    * known as Encoding.Unicode. Other encodings may exist as  * 
    * Byte-Array or incorrectly stored with the UTF-16 encoding. * 
    *                * 
    * UTF-8 = 1 bytes per char         * 
    * ["100" for the ansi 'd']         * 
    * ["206" and "186" for the russian '?']     * 
    *                * 
    * UTF-16 = 2 bytes per char         * 
    * ["100, 0" for the ansi 'd']        * 
    * ["186, 3" for the russian '?']       * 
    *                * 
    * UTF-8 inside UTF-16           * 
    * ["100, 0" for the ansi 'd']        * 
    * ["206, 0" and "186, 0" for the russian '?']    * 
    *                * 
    * First we need to get the UTF-8 Byte-Array and remove all * 
    * 0 byte (binary 0) while doing so.       * 
    *                * 
    * Binary 0 means end of string on UTF-8 encoding while on  * 
    * UTF-16 one binary 0 does not end the string. Only if there * 
    * are 2 binary 0, than the UTF-16 encoding will end the  * 
    * string. Because of .NET we don't have to handle this.  * 
    *                * 
    * After removing binary 0 and receiving the Byte-Array, we * 
    * can use the UTF-8 encoding to string method now to get a * 
    * UTF-16 string.            * 
    *                * 
    ***************************************************************/ 

    // Get UTF-8 bytes and remove binary 0 bytes (filler) 
    List<byte> utf8Bytes = new List<byte>(utf8String.Length); 
    foreach (byte utf8Byte in utf8String) 
    { 
     // Remove binary 0 bytes (filler) 
     if (utf8Byte > 0) { 
      utf8Bytes.Add(utf8Byte); 
     } 
    } 

    // Convert UTF-8 bytes to UTF-16 string 
    return Encoding.UTF8.GetString(utf8Bytes.ToArray()); 
} 

मेरे मामले में DLL परिणाम एक UTF-8 स्ट्रिंग बहुत होता है, लेकिन दुर्भाग्य से UTF-8 तार के साथ UTF-16 एन्कोडिंग ('O' व्याख्या की है: निम्न का उपयोग कर सकते ], [1 9, 32])। तो एएनएसआई '-' जो 150 है UTF-16 के लिए परिवर्तित कर दिया गया '-' है जो 8211. आप इस मामले में भी है, तो आप के बजाय निम्न का उपयोग कर सकते हैं:

public static string Utf8ToUtf16(string utf8String) 
{ 
    // Get UTF-8 bytes by reading each byte with ANSI encoding 
    byte[] utf8Bytes = Encoding.Default.GetBytes(utf8String); 

    // Convert UTF-8 bytes to UTF-16 bytes 
    byte[] utf16Bytes = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, utf8Bytes); 

    // Return UTF-16 bytes as UTF-16 string 
    return Encoding.Unicode.GetString(utf16Bytes); 
} 

या देशी-विधि :

[DllImport("kernel32.dll")] 
private static extern Int32 MultiByteToWideChar(UInt32 CodePage, UInt32 dwFlags, [MarshalAs(UnmanagedType.LPStr)] String lpMultiByteStr, Int32 cbMultiByte, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpWideCharStr, Int32 cchWideChar); 

public static string Utf8ToUtf16(string utf8String) 
{ 
    Int32 iNewDataLen = MultiByteToWideChar(Convert.ToUInt32(Encoding.UTF8.CodePage), 0, utf8String, -1, null, 0); 
    if (iNewDataLen > 1) 
    { 
     StringBuilder utf16String = new StringBuilder(iNewDataLen); 
     MultiByteToWideChar(Convert.ToUInt32(Encoding.UTF8.CodePage), 0, utf8String, -1, utf16String, utf16String.Capacity); 

     return utf16String.ToString(); 
    } 
    else 
    { 
     return String.Empty; 
    } 
} 

यदि आपको इसे दूसरी तरफ की आवश्यकता है, तो Utf16ToUtf8 देखें। आशा है कि मैं मदद की हो सकती है।

+0

बस यह सुनिश्चित करने के लिए: कनवर्ट करने के बाद स्ट्रिंग अभी भी यूटीएफ -16 होगी, इसमें केवल यूटीएफ -8 एन्कोडिंग डेटा होगा। आप यूटीएफ -8 एन्कोडिंग का उपयोग कर तारों को संभाल नहीं सकते हैं, क्योंकि .NET हमेशा तारों को संभालने के लिए यूटीएफ -16 एन्कोडिंग का उपयोग करेगा। – MEN

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