2009-06-08 11 views
9

निम्नलिखित कोड पर विचार करें:हैंडलिंग यूनिकोड सरोगेट मूल्यों

byte aBytes[] = { (byte)0xff,0x01,0,0, 
        (byte)0xd9,(byte)0x65, 
        (byte)0x03,(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, 
        (byte)0x17,(byte)0x33, (byte)0x74, (byte)0x6f, 
        0, 1, 2, 3, 4, 5, 
        0 }; 
String sCompressedBytes = new String(aBytes, "UTF-16"); 
for (int i=0; i<sCompressedBytes.length; i++) { 
    System.out.println(Integer.toHexString(sCompressedBytes.codePointAt(i))); 
} 

हो जाता है निम्नलिखित गलत उत्पादन:

ff01, 0, fffd, 506, 717, 3374, 6f00, 102, 304, 500. 

हालांकि, अगर इनपुट डेटा में 0xd90x9d करने के लिए बदल जाता है, तो निम्नलिखित सही उत्पादन प्राप्त किया जाता है:

ff01, 0, 9d65, 304, 506, 717, 3374, 6f00, 102, 304, 500. 

मैं reali ज़ी है कि कार्यक्षमता इस तथ्य के कारण है कि बाइट 0xd9 एक उच्च-सरोगेट यूनिकोड मार्कर है।

प्रश्न: जावा यूनिकोड स्ट्रिंग में सरोगेट बाइट्स (0xd800 से 0xdfff) को खिलाने, पहचानने और निकालने का कोई तरीका है?
धन्यवाद

उत्तर

4

वहाँ, खिलाने की पहचान करने और निकालने के एक जावा यूनिकोड स्ट्रिंग में किराए की बाइट (0xdfff को 0xd800) करने के लिए एक रास्ता है ?

सिर्फ इसलिए कि किसी ने इसका उल्लेख नहीं किया है, मैं बताउंगा कि Character कक्षा में सरोगेट जोड़े के साथ काम करने के तरीके शामिल हैं। जैसे isHighSurrogate(char), codePointAt(CharSequence, int) और toChars(int)। मुझे एहसास है कि यह बताई गई समस्या के बिंदु के अलावा है।

new String(aBytes, "UTF-16"); 

यह एक डिकोडिंग आपरेशन कि इनपुट डेटा को बदलने जाएगा।मुझे पूरा यकीन है कि यह कानूनी नहीं है क्योंकि चयनित डिकोडिंग ऑपरेशन को इनपुट को 0xfe 0xff या 0xff 0xfe (byte order mark) से शुरू करने की आवश्यकता होती है। इसके अतिरिक्त, प्रत्येक संभावित बाइट मान को सही ढंग से डीकोड नहीं किया जा सकता है क्योंकि यूटीएफ -16 variable width encoding है।

आप स्ट्रिंग के लिए मनमाने ढंग से बाइट्स की एक सममित परिवर्तन चाहता था और वापस, आप एक 8 बिट, एकल-बाइट एन्कोडिंग के साथ बेहतर कर रहे हैं, क्योंकि हर बाइट मूल्य मान्य वर्ण नहीं है, तो:

Charset iso8859_15 = Charset.forName("ISO-8859-15"); 
byte[] data = new byte[256]; 
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { 
    data[i - Byte.MIN_VALUE] = (byte) i; 
} 
String asString = new String(data, iso8859_15); 
byte[] encoded = asString.getBytes(iso8859_15); 
System.out.println(Arrays.equals(data, encoded)); 

नोट: पात्रों की संख्या बाइट्स की संख्या के बराबर होगी (डेटा के आकार को दोगुनी); परिणामस्वरूप स्ट्रिंग आवश्यक रूप से प्रिंट करने योग्य नहीं है (जैसा कि यह हो सकता है, bunch of control characters)।

मैं with Jon हूं, हालांकि - जावा स्ट्रिंग्स में मनमाने ढंग से बाइट अनुक्रम डालना लगभग हमेशा एक बुरा विचार है।

10

संपादित करें: यह टिप्पणी

आप एक स्ट्रिंग में मनमाने ढंग से बाइनरी डेटा सांकेतिक शब्दों में बदलना चाहते हैं से सवाल को संबोधित करता है, तो आप नहीं एक सामान्य पाठ एन्कोडिंग का उपयोग करना चाहिए। आपके पास उस एन्कोडिंग में वैध टेक्स्ट नहीं है - आपके पास मनमाने ढंग से बाइनरी डेटा है।

Base64 यहां जाने का तरीका है। जावा (सीधे सार्वजनिक कक्षा में) में कोई आधार 64 समर्थन नहीं है, लेकिन आप विभिन्न तृतीय पक्ष पुस्तकालयों का उपयोग कर सकते हैं, जैसे कि the one in the Apache Commons Codec library

हां, बेस 64 डेटा के आकार में वृद्धि करेगा - लेकिन यह आपको सूचना खोने के बाद बाद में इसे डीकोड करने की अनुमति देगा।

संपादित करें: इस मूल प्रश्न

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

यहाँ इस प्रदर्शन करने के लिए कोड है:

public class Test 
{ 
    public static void main(String[] args) 
     throws Exception // Just for simplicity 
    { 
     byte[] data = 
     { 
      0, 0x41, // A 
      (byte) 0xD8, 1, // High surrogate 
      (byte) 0xDC, 2, // Low surrogate 
      0, 0x42, // B 
     }; 

     String text = new String(data, "UTF-16"); 

     System.out.printf("%x\r\n", text.codePointAt(0)); 
     System.out.printf("%x\r\n", text.codePointAt(1)); 
     // Code point at 2 is part of the surrogate pair 
     System.out.printf("%x\r\n", text.codePointAt(3));  
    } 
} 

आउटपुट:

41 
10402 
42 
+0

मुझे विश्वास है कि आप सही हैं। मैं बस एक ही निष्कर्ष पर आया था लेकिन यह देखने के लिए वापस जांच की गई कि क्या कोई और जानकार पहले ही उत्तर दे चुका है या नहीं। –

+0

सीधे शब्दों में डालने "(बाइट) 0xdc, (बाइट) 0xef," पैदावार "FF01 694ef dcef ..." है कौन सा रूप में यह होना चाहिए। –

+0

आपके उत्तरों के लिए धन्यवाद। लेकिन, समस्या सरोगेट पात्रों को एम्बेड करने के बारे में नहीं है। जावा स्ट्रिंग में किसी भी मनमानी बाइट अनुक्रम (जो संपीड़न से आउटपुट होते हैं) को खिलाना और इसे बराबर बाइट अनुक्रम के रूप में वापस पढ़ने के लिए आवश्यकता है। –

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