首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ICU (ICU4C)读取UTF-8编码文件的缓冲区大小

使用ICU (ICU4C)读取UTF-8编码文件的缓冲区大小
EN

Stack Overflow用户
提问于 2013-07-07 11:35:54
回答 2查看 2.1K关注 0票数 1

我正在尝试使用ICU4C和msvc11在Windows上读取UTF-8编码的文件.我需要确定缓冲区的大小来构建一个UnicodeString。由于在ICU4C API中没有类似file的函数,所以我想我可以使用一个底层C文件:

代码语言:javascript
复制
#include <unicode/ustdio.h>
#include <stdio.h>
/*...*/
UFILE *in = u_fopen("utfICUfseek.txt", "r", NULL, "UTF-8");
FILE* inFile = u_fgetfile(in);
fseek(inFile,  0, SEEK_END); /* Access violation here */
int size = ftell(inFile);
auto uChArr = new UChar[size];

此代码有两个问题:

  1. 它“抛出”访问冲突,因为某些原因(在ntdll.dll: 0xC0000005:访问冲突写入位置0x0000000024中,0x000007FC5451AB00 (ntdll.dll)处有未处理的异常)。
  2. ftell函数返回的大小将不是我想要的大小,因为UTF-8可以使用最多4个字节作为代码点( u8"tю“字符串的长度为3)。

所以问题是:

  1. 如果我知道输入文件是UTF-8编码的,那么如何确定UnicodeString的缓冲区大小?
  2. 是否有一种可移植的方法可以同时使用iostream/fstream来读取和写入ICU的UnicodeStrings?

编辑:这是可能的解决方案(在msvc11和gcc 4.8.1上测试),基于第一个答案和C++11标准。国际标准化组织,IEC,14882,2011年的几件事:

  1. C++内存模型中的基本存储单元是字节。字节至少足够大,足以包含基本执行字符集(2.3) 和Unicode UTF-8编码形式的8位代码单元的任何成员.
  2. “基本源字符集由96个字符组成.”,-7位
  3. “基本执行字符集和基本执行宽字符集应各自包含基本源字符集的所有成员.”
  4. 声明为字符(char)的对象应该足够大,足以存储实现基本字符集的任何成员。

因此,要使这种可移植性适用于实现定义的char大小为1字节=8位(不知道哪里不正确)的平台,我们可以使用未格式化的输入操作将Unicode字符读入字符:

代码语言:javascript
复制
std::ifstream is;
is.open("utfICUfSeek.txt");
is.seekg(0, is.end);
int strSize = is.tellg();
auto inputCStr = new char[strSize + 1];
inputCStr[strSize] = '\0'; //add null-character at the end
is.seekg(0, is.beg);
is.read(inputCStr, strSize);
is.seekg(0, is.beg);
UnicodeString uStr = UnicodeString::fromUTF8(inputCStr);
is.close();

困扰我的是,我必须为字符创建一个额外的缓冲区,然后才能将它们转换为所需的UnicodeString。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-08 03:37:38

这是使用ICU的另一种选择。

使用标准的std::fstream,您可以将文件的整个/部分读入标准的std::string中,然后使用具有unicode感知的迭代器对其进行迭代。http://code.google.com/p/utf-iter/

代码语言:javascript
复制
std::string get_file_contents(const char *filename)
{
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (in)
    {
        std::string contents;
        in.seekg(0, std::ios::end);
        contents.reserve(in.tellg());
        in.seekg(0, std::ios::beg);
        contents.assign((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
        in.close();
        return(contents);
    }
    throw(errno);
}

然后在你的代码中

代码语言:javascript
复制
std::string myString = get_file_contents( "foobar" );
unicode::iterator< std::string, unicode::utf8 /* or utf16/32 */ > iter = myString.begin();

while ( iter != myString.end() )
{
    ...
    ++iter;
}
票数 2
EN

Stack Overflow用户

发布于 2014-08-29 16:50:19

好吧,如果您想一次读取整个文件进行某种后处理,在这种情况下,icu::UnicodeString并不是最好的容器…

代码语言:javascript
复制
#include <iostream>
#include <fstream>
#include <sstream>

int main()
{
    std::ifstream in( "utfICUfSeek.txt" );
    std::stringstream buffer;
    buffer << in.rdbuf();
    in.close();
    // ...
    return 0;
}

...or你真正想要的是读进icu::UnicodeString,就像读到任何其他字符串对象一样,但是却走了很远的路……

代码语言:javascript
复制
#include <iostream>
#include <fstream>

#include <unicode/unistr.h>
#include <unicode/ustream.h>

int main()
{
    std::ifstream in( "utfICUfSeek.txt" );
    icu::UnicodeString uStr;
    in >> uStr;
    // ...
    in.close();
    return 0;
}

...or我完全想不起你真正的问题是什么。;)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17511783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档