代码之家  ›  专栏  ›  技术社区  ›  Harvey

在Linux中,如何使用POSIX方法从文件中读取Unicode-16字符串?

  •  5
  • Harvey  · 技术社区  · 16 年前

    我有一个包含unicode-16字符串的文件,我想把它读到Linux程序中。字符串是从Windows的内部wchar格式原始写入的。(Windows是否总是使用UTF-16?例如,在日语版本中)

    我相信我可以使用原始读取和wcstombs转换来读取它们,但是我无法确定要使用的区域设置。在我最新的Ubuntu和MacOSX机器上运行“locale-a”,可以生成零个以utf-16命名的区域设置。

    有更好的方法吗?

    更新:正确的答案和下面的其他帮助我指出使用libiconv。这是我用来做转换的函数。我现在把它放在一个类中,这个类将转换成一行代码。

    // Function for converting wchar_t* to char*. (Really: UTF-16LE --> UTF-8)
    // It will allocate the space needed for dest. The caller is
    // responsible for freeing the memory.
    static int iwcstombs_alloc(char **dest, const wchar_t *src)
    {
      iconv_t cd;
      const char from[] = "UTF-16LE";
      const char to[] = "UTF-8";
    
      cd = iconv_open(to, from);
      if (cd == (iconv_t)-1)
      {
        printf("iconv_open(\"%s\", \"%s\") failed: %s\n",
               to, from, strerror(errno));
        return(-1);
      }
    
      // How much space do we need?
      // Guess that we need the same amount of space as used by src.
      // TODO: There should be a while loop around this whole process
      //       that detects insufficient memory space and reallocates
      //       more space.
      int len = sizeof(wchar_t) * (wcslen(src) + 1);
    
      //printf("len = %d\n", len);
    
      // Allocate space
      int destLen = len * sizeof(char);
      *dest = (char *)malloc(destLen);
      if (*dest == NULL)
      {
        iconv_close(cd);
        return -1;
      }
    
      // Convert
    
      size_t inBufBytesLeft = len;
      char *inBuf = (char *)src;
      size_t outBufBytesLeft = destLen;
      char *outBuf = (char *)*dest;
    
      int rc = iconv(cd,
                     &inBuf,
                     &inBufBytesLeft,
                     &outBuf,
                     &outBufBytesLeft);
      if (rc == -1)
      {
        printf("iconv() failed: %s\n", strerror(errno));
        iconv_close(cd);
        free(*dest);
        *dest = NULL;
        return -1;
      }
    
      iconv_close(cd);
    
      return 0;
    } // iwcstombs_alloc()
    
    4 回复  |  直到 14 年前
        1
  •  4
  •   bobince    16 年前

    (Windows是否总是使用UTF-16?例如,在日语版本中)

    是的,NT的wchar总是utf-16le。

    (对于日本安装的__System codepage_,实际上是CP932/SHIFT JIS,为了许多非Unicode本机、FAT32路径等应用程序的利益,NT中仍然存在。)

    但是,wchar-t不能保证是16位的,在Linux上,它不能保证是16位的,使用的是utf-32(ucs-4)。所以wcstombs不太可能快乐。

    正确的做法是使用像iconv这样的库,以内部使用的任何格式读取它——大概是wchar_t。 能够 试着自己通过插入字节来破解它,但是你可能会把代理程序搞错。

    在我最新的Ubuntu和MacOSX机器上运行“locale-a”,可以生成零个以utf-16命名的区域设置。

    事实上,由于所有的\0,Linux不能使用UTF-16作为区域设置默认编码。

        2
  •  6
  •   Artyom    16 年前

    最简单的方法是将文件从utf16转换为utf8本机UNIX编码,然后读取它,

    iconv -f utf16 -t utf8 file_in.txt -o file_out.txt
    

    您还可以使用ICONV(3)(请参阅man 3 ICONV)使用C转换字符串。大多数其他语言也具有到ICONV的绑定。

    您可以使用任何像en-us.utf-8这样通常是默认的utf-8语言环境 在大多数Linux发行版上。

        3
  •  2
  •   Mihai Nita    16 年前

    您可以读取为二进制文件,然后进行自己的快速转换: http://unicode.org/faq/utf_bom.html#utf16-3 但使用一个能正确处理无效序列的库(如libiconv)可能更安全。

        4
  •  1
  •   Adam Rosenfield    16 年前

    我强烈建议使用Unicode编码作为程序的内部表示。使用utf-16或utf-8。如果您在内部使用UTF-16,那么显然不需要翻译。如果使用UTF-8,则可以将区域设置与 .UTF-8 在其中,如 en_US.UTF-8 .