如何在Linux上用C获取文件中的字符数(而不是字节数)

如何在Linux上用C获取文件中的字符数(而不是字节数),c,linux,unicode,encoding,C,Linux,Unicode,Encoding,我想获取文件中的字符数。我所说的字符是指“真实”字符,而不是字节。假设我知道文件编码 我试图使用mbstowcs(),但它不起作用,因为它使用了系统区域设置(或使用setlocale定义的区域设置)。因为setlocale不是线程安全的,所以我认为在调用mbstowcs()之前使用它不是一个好主意。即使是安全的,我也要确保 我的程序不会在调用setlocale()之间“跳转”(信号等)(一次调用将其设置为文件编码,一次调用将其还原为上一次调用) 因此,举个例子,假设我们有一个文件ru.txt,使

我想获取文件中的字符数。我所说的字符是指“真实”字符,而不是字节。假设我知道文件编码

我试图使用
mbstowcs()
,但它不起作用,因为它使用了系统区域设置(或使用setlocale定义的区域设置)。因为setlocale不是线程安全的,所以我认为在调用
mbstowcs()
之前使用它不是一个好主意。即使是安全的,我也要确保 我的程序不会在调用
setlocale()
之间“跳转”(信号等)(一次调用将其设置为文件编码,一次调用将其还原为上一次调用)

因此,举个例子,假设我们有一个文件ru.txt,使用俄语编码(例如KOI8)。因此,我想打开文件并获取字符数,假设文件的编码是KOI8

如果
mbstowcs()
可以采用
source\u编码
参数,那就很容易了

编辑:使用
mbstowcs()
的另一个问题是,必须在系统上安装与文件编码对应的区域设置…

我建议使用iconv(3):

名称
iconv-执行字符集转换
提要
#包括
尺寸图标(图标cd,
字符**inbuf,大小*inbytesleft,
字符**EXPUF,大小*OUTBYTESLEET);

并转换为utf32。每转换一个字符就有4字节的输出(BOM表加上2字节)。如果仔细选择outbytesleft(即4*inbytesleft+2:-),则可以使用固定大小的EXBUFF逐段转换输入。要计算文件中的UTF8字符数,只需将其内容传递到此函数:

int CalcUTF8Chars( const std::string& S )
{
    int Count = 0;

    for ( size_t i = 0; i != S.length(); i++ )
    {
        if ( ( S[i] & 0xC0 ) != 0x80 ) { Count++; }
    }

    return Count;
}
没有外部依赖关系

更新:

如果要处理其他不同的编码,您有两种选择:

  • 使用能够处理它的第三方库,例如ICU

  • 为您想要使用的每种编码自己编写计算函数


  • 我认为您可以通过选择具有定义字节顺序的输出编码(例如“UTF-32BE”)来摆脱BOM。通过选择具有定义字节顺序的输出编码(例如“UTF-32BE”)来摆脱BOM。=>是的,你是对的,事实确实如此,至少在iconv(1)程序中是这样。这应该可以工作,但我不能在EXPUF:strlen等上使用任何字符串操作函数。我必须编写一个utf32_strlen()函数,将strlen()/4和减2分开。有更好的方法吗?@ThibautD.:
    iconv()
    返回转换后的字符数,因此无需确定转换后字符串的长度。@ThibautD.:在我的Linux系统上,
    iconv--list
    的输出显示“WCHAR\u T”也是受支持的输出编码。-BTW.你的问题只是计算字符数,所以我不认为这个答案是“固定到一个特殊的情况”,而是解决你的问题。在我的例子中,我的文件没有被编码在UTF-8中。我正在寻找一种可移植的方法,而不是为每个编码都编写一个函数。您的文件的编码是什么?您的问题被标记为UNICODE。它可以是任何编码。这是一个一般性的问题。我只是假设我们知道编码。问题(据我所知)是关于计算文件中指定编码的字符数,而不是计算UTF-8字符数。但是您的问题被标记为
    unicode
    ,并且您提到了Linux上的UTF8。
    int CalcUTF8Chars( const std::string& S )
    {
        int Count = 0;
    
        for ( size_t i = 0; i != S.length(); i++ )
        {
            if ( ( S[i] & 0xC0 ) != 0x80 ) { Count++; }
        }
    
        return Count;
    }