2012-06-22 14 views
7

मेरा सॉफ़्टवेयर यूटीएफ 8 में कुछ स्ट्रिंग प्राप्त कर रहा है, मुझे आईएसओ 885 9 में कनवर्ट करने की आवश्यकता है। मुझे पता है कि यूटीएफ 8 डोमेन आईएसओ 885 9 से बड़ा है। लेकिन यूटीएफ 8 में डेटा पहले आईएसओ से अपवर्तन किया गया है, इसलिए मुझे कुछ याद नहीं करना चाहिए।क्या यूटीएफ 8 से आईएसओ -885 9 -1 में परिवर्तित करने का कोई तरीका है?

मैं जानना चाहता हूं कि यूटीएफ 8 से आईएसओ -885 9 -1 में परिवर्तित करने का एक आसान/सीधा तरीका है या नहीं।

धन्यवाद

+1

यदि आप एक लाइब्रेरी का उपयोग कर रहे हैं जिसने रूपांतरण किया है, तो इसे वापस बदलने के लिए कुछ भी होना चाहिए। मान लीजिए कि आपने स्ट्रिंग में किसी भी वर्ण को नहीं बदला है, आपको बस इसे वापस देने के लिए ठीक होना चाहिए। – RedX

उत्तर

11

यहाँ एक समारोह जो आपके लिए उपयोगी हो सकता है: utf8_to_latin9()। यह ISO-8859-15 (यूरो सहित, ISO-8859-1 में नहीं है) में परिवर्तित होता है, लेकिन UTF-8 - ISO-8859-1ISO-8859-1 - ->ISO-8859-1 राउंड-ट्रिप के रूपांतरण भाग के लिए सही ढंग से काम करता है।

फ़ंक्शन आइकनव के लिए //IGNORE ध्वज के समान अमान्य कोड बिंदुओं को अनदेखा करता है, लेकिन विघटित यूटीएफ -8 अनुक्रमों को पुन: संकलित नहीं करता है; यानी, यह U+006E U+0303 को U+00F1 में नहीं बदलेगा। मैं recomposing परेशान नहीं है क्योंकि iconv या तो नहीं है।

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

/* UTF-8 to ISO-8859-1/ISO-8859-15 mapper. 
* Return 0..255 for valid ISO-8859-15 code points, 256 otherwise. 
*/ 
static inline unsigned int to_latin9(const unsigned int code) 
{ 
    /* Code points 0 to U+00FF are the same in both. */ 
    if (code < 256U) 
     return code; 
    switch (code) { 
    case 0x0152U: return 188U; /* U+0152 = 0xBC: OE ligature */ 
    case 0x0153U: return 189U; /* U+0153 = 0xBD: oe ligature */ 
    case 0x0160U: return 166U; /* U+0160 = 0xA6: S with caron */ 
    case 0x0161U: return 168U; /* U+0161 = 0xA8: s with caron */ 
    case 0x0178U: return 190U; /* U+0178 = 0xBE: Y with diaresis */ 
    case 0x017DU: return 180U; /* U+017D = 0xB4: Z with caron */ 
    case 0x017EU: return 184U; /* U+017E = 0xB8: z with caron */ 
    case 0x20ACU: return 164U; /* U+20AC = 0xA4: Euro */ 
    default:  return 256U; 
    } 
} 

/* Convert an UTF-8 string to ISO-8859-15. 
* All invalid sequences are ignored. 
* Note: output == input is allowed, 
* but input < output < input + length 
* is not. 
* Output has to have room for (length+1) chars, including the trailing NUL byte. 
*/ 
size_t utf8_to_latin9(char *const output, const char *const input, const size_t length) 
{ 
    unsigned char    *out = (unsigned char *)output; 
    const unsigned char  *in = (const unsigned char *)input; 
    const unsigned char *const end = (const unsigned char *)input + length; 
    unsigned int    c; 

    while (in < end) 
     if (*in < 128) 
      *(out++) = *(in++); /* Valid codepoint */ 
     else 
     if (*in < 192) 
      in++;    /* 10000000 .. 10111111 are invalid */ 
     else 
     if (*in < 224) {  /* 110xxxxx 10xxxxxx */ 
      if (in + 1 >= end) 
       break; 
      if ((in[1] & 192U) == 128U) { 
       c = to_latin9((((unsigned int)(in[0] & 0x1FU)) << 6U) 
          | ((unsigned int)(in[1] & 0x3FU))); 
       if (c < 256) 
        *(out++) = c; 
      } 
      in += 2; 

     } else 
     if (*in < 240) {  /* 1110xxxx 10xxxxxx 10xxxxxx */ 
      if (in + 2 >= end) 
       break; 
      if ((in[1] & 192U) == 128U && 
       (in[2] & 192U) == 128U) { 
       c = to_latin9((((unsigned int)(in[0] & 0x0FU)) << 12U) 
          | (((unsigned int)(in[1] & 0x3FU)) << 6U) 
          | ((unsigned int)(in[2] & 0x3FU))); 
       if (c < 256) 
        *(out++) = c; 
      } 
      in += 3; 

     } else 
     if (*in < 248) {  /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 
      if (in + 3 >= end) 
       break; 
      if ((in[1] & 192U) == 128U && 
       (in[2] & 192U) == 128U && 
       (in[3] & 192U) == 128U) { 
       c = to_latin9((((unsigned int)(in[0] & 0x07U)) << 18U) 
          | (((unsigned int)(in[1] & 0x3FU)) << 12U) 
          | (((unsigned int)(in[2] & 0x3FU)) << 6U) 
          | ((unsigned int)(in[3] & 0x3FU))); 
       if (c < 256) 
        *(out++) = c; 
      } 
      in += 4; 

     } else 
     if (*in < 252) {  /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 
      if (in + 4 >= end) 
       break; 
      if ((in[1] & 192U) == 128U && 
       (in[2] & 192U) == 128U && 
       (in[3] & 192U) == 128U && 
       (in[4] & 192U) == 128U) { 
       c = to_latin9((((unsigned int)(in[0] & 0x03U)) << 24U) 
          | (((unsigned int)(in[1] & 0x3FU)) << 18U) 
          | (((unsigned int)(in[2] & 0x3FU)) << 12U) 
          | (((unsigned int)(in[3] & 0x3FU)) << 6U) 
          | ((unsigned int)(in[4] & 0x3FU))); 
       if (c < 256) 
        *(out++) = c; 
      } 
      in += 5; 

     } else 
     if (*in < 254) {  /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 
      if (in + 5 >= end) 
       break; 
      if ((in[1] & 192U) == 128U && 
       (in[2] & 192U) == 128U && 
       (in[3] & 192U) == 128U && 
       (in[4] & 192U) == 128U && 
       (in[5] & 192U) == 128U) { 
       c = to_latin9((((unsigned int)(in[0] & 0x01U)) << 30U) 
          | (((unsigned int)(in[1] & 0x3FU)) << 24U) 
          | (((unsigned int)(in[2] & 0x3FU)) << 18U) 
          | (((unsigned int)(in[3] & 0x3FU)) << 12U) 
          | (((unsigned int)(in[4] & 0x3FU)) << 6U) 
          | ((unsigned int)(in[5] & 0x3FU))); 
       if (c < 256) 
        *(out++) = c; 
      } 
      in += 6; 

     } else 
      in++;    /* 11111110 and 11111111 are invalid */ 

    /* Terminate the output string. */ 
    *out = '\0'; 

    return (size_t)(out - (unsigned char *)output); 
} 

ध्यान दें कि आप to_latin9() समारोह में विशिष्ट कोड अंक के लिए कस्टम लिप्यंतरण जोड़ सकते हैं, लेकिन आप एक चरित्र प्रतिस्थापन तक सीमित हैं।

जैसा कि वर्तमान में लिखा गया है, फ़ंक्शन इन-प्लेस रूपांतरण सुरक्षित रूप से कर सकता है: इनपुट और आउटपुट पॉइंटर्स समान हो सकते हैं। आउटपुट स्ट्रिंग इनपुट स्ट्रिंग से कभी अधिक नहीं होगी। यदि आपकी इनपुट स्ट्रिंग में अतिरिक्त बाइट के लिए कमरा है (उदाहरण के लिए, इसमें एनयूएल स्ट्रिंग को समाप्त कर रहा है), तो आप उपरोक्त फ़ंक्शन को यूटीएफ -8 से आईएसओ -8859-1/15 में परिवर्तित करने के लिए सुरक्षित रूप से उपयोग कर सकते हैं। मैंने जानबूझकर इसे इस तरह लिखा है, क्योंकि इसे आपको एम्बेडेड वातावरण में कुछ प्रयास करना चाहिए, हालांकि यह दृष्टिकोण थोड़ा सीमित wrt है। अनुकूलन और विस्तार।

संपादित करें:

मैं के लिए रूपांतरण कार्यों in an edit to this answer की एक जोड़ी शामिल दोनों लैटिन -1/9/UTF-8 रूपांतरण से (आईएसओ-8859-1 या -15 से/UTF-8); मुख्य अंतर यह है कि वे कार्य गतिशील रूप से आवंटित प्रतिलिपि लौटाते हैं, और मूल स्ट्रिंग को बरकरार रखते हैं।

10

iconv -

size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);

iconv_t iconv_open(const char *tocode, const char *fromcode);

tocode"ISO_8859-1" और fromcode है "UTF-8" है प्रदर्शन वर्ण सेट रूपांतरण।

कार्य उदाहरण:

#include <iconv.h> 
#include <stdio.h> 

int main (void) { 
    iconv_t cd = iconv_open("ISO_8859-1", "UTF-8"); 
    if (cd == (iconv_t) -1) { 
     perror("iconv_open failed!"); 
     return 1; 
    } 

    char input[] = "Test äöü"; 
    char *in_buf = &input[0]; 
    size_t in_left = sizeof(input) - 1; 

    char output[32]; 
    char *out_buf = &output[0]; 
    size_t out_left = sizeof(output) - 1; 

    do { 
     if (iconv(cd, &in_buf, &in_left, &out_buf, &out_left) == (size_t) -1) { 
      perror("iconv failed!"); 
      return 1; 
     } 
    } while (in_left > 0 && out_left > 0); 
    *out_buf = 0; 

    iconv_close(cd); 

    printf("%s -> %s\n", input, output); 
    return 0; 
} 
+0

धन्यवाद, मेरे पास मुख्य समस्या है और मैं यह निर्दिष्ट करना भूल गया कि मेरा सॉफ़्टवेयर एम्बेडेड लिनक्स पर चलता है और iconv उपलब्ध नहीं है। – fazineroso

+0

आप अपने लिनक्स के लिए iconv संकलित कर सकते हैं। क्या आपका लिनक्स ग्लिब का उपयोग करता है? यदि हां, तो इसका 'gconv' नामक संगत कार्यान्वयन है: http://www.gnu.org/software/libc/manual/html_node/glibc-iconv-Implementation.html –

+0

@fazineroso ऐसे समाधान हैं जो लाइब्रेरी को नियोजित नहीं करते हैं कहता है। मुझे अब जाना होगा, लेकिन यदि आप कल या उससे बेहतर नहीं पाते हैं तो मैं अपना जवाब अपडेट कर दूंगा। – kay

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

  • कोई संबंधित समस्या नहीं^_^