2012-02-10 22 views
6

我想要计算文件中的字符(以各种字符集),并使用函数'mbtowc'来检测字符。我无法弄清楚为什么字符和结果值是不同的。这是我的例子:为什么mbtowc不按预期计数字符集?

char buf[BUFFER_SIZE + MB_LEN_MAX]; 

int fd = open ("chinese_test", O_RDONLY); 

unsigned int bytes, chars; 

int bytes_read; 

bytes = chars = 0; 

while((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0) { 
    wchar_t wc_buf[BUFFER_SIZE], *wcp; 
    char *p; 
    int n = 0; 

    bytes += bytes_read; 

    p = buf; 
    wcp = wc_buf; 

    while((n = mbtowc(wcp, p, MB_LEN_MAX)) > 0) { 
     p += n; 
     wcp++; 

     chars++; 
    } 

} 

printf("chars: %d\tbytes: %d\n", chars, bytes); 

我测试的功能与一些GB2312字符的文本,但字符字节太多不同的值。

我的测试返回 - >字符:4638 |字节:17473 但'wc'linux命令返回:字符:16770 |字节:17473

为什么这个区别?我做错了什么?


现在我已经有了这段代码,但结果仍然存在差异。

char buf[BUFFER_SIZE * MB_LEN_MAX]; 

int fd = open ("test_chinese", O_RDONLY), filled = 0; 

unsigned int bytes, chars; 

int bytes_read; 

bytes = chars = 0; 

while((bytes_read = read(fd, buf, BUFFER_SIZE)) > 0) { 
    wchar_t wc_buf[BUFFER_SIZE], *wcp; 
    char *p; 
    int n = 0; 

    bytes += bytes_read; 

    p = buf; 
    wcp = wc_buf; 



    while(bytes_read > 0) { 
     n = mbtowc(NULL, p, MB_LEN_MAX); 

     if (n <= 0) { 
      p++; 
      bytes_read--; 
      continue; 
     } 
     p += n; 

     bytes_read -= n; 

     chars++; 
    } 

} 

printf("\n\nchars: %d\tbytes: %d\n", chars, bytes); 
+2

,你可能会得到不完整的多字节序列。在'while'循环后面加上一个检查来确定'n'是否为负。 – 2012-02-10 01:32:39

+0

@JoachimPileborg,我知道这个问题。有可能是17473字节的文件和BUFFER_SIZE = 1024有这么多的错误吗? – Figus 2012-02-10 01:42:56

+0

可能不是,但你应该检查这个。瑞士人答复中指出的最可能的罪魁祸首是。 – 2012-02-10 01:48:27

回答

6

的问题是你的BUFFER_SIZE的组合,chinese_test文件大小和wchar_t字节对齐。作为证据,尝试大幅增加BUFFER_SIZE - 你应该开始得到你想要的答案。

发生了什么事是您的程序适用于它接收的第一个文本块。不过,仔细想想,如果一个角色在第一和第二块之间的分割如下的代码会发生什么:

| First Block     | Second Block  | 
    | [wchar_t] [wchar_t] ... [wchar_t] [wchar_t] ... | 
    | [1,2,3,4] [1,2,3,4] ... [1,2,3,4] [1,2,3,4] ... | 

您的代码将开始的第一个字符的第3个字节的第二块,而不会是被认为是有效的人物。由于mbtowc将返回-1当它找不到有效的字符时,您的循环将立即结束并将计数整个块的零个字符。以下方块也适用。

编辑:
我注意到的另一个问题是,您需要设置区域设置,以使mbtowc正常工作。考虑到所有这些问题考虑在内,我写了返回相同的字符数为wc我的情况如下:根据你`BUFFER_SIZE`,并且阅读了文件的大小

#include <stdlib.h> 
#include <stdio.h> 
#include <locale.h> 

int BUFFER_SIZE = 1024; 
const char *DEFAULT_F_IN = "chinese_test"; 

struct counts { 
    int bytes; 
    int chars; 
}; 

int count_block(struct counts *c, char *buf, int buf_size) 
{ 
    int offset = 0; 
    while (offset < buf_size) { 
     int n = mbtowc(NULL, buf + offset, MB_CUR_MAX); 
     if (n <= 0) { 
      break; 
     } 

     offset += n; 
     c->bytes += n; 
     c->chars++; 
    } 

    return buf_size - offset; 
} 

void get_counts(struct counts *c, FILE *fd) 
{ 
    char buf[BUFFER_SIZE]; 
    c->bytes = 0; 
    c->chars = 0; 

    int bytes_read; 
    while((bytes_read = fread(buf, sizeof(*buf), BUFFER_SIZE, fd)) > 0) { 
     int remaining = count_block(c, buf, bytes_read); 
     if (remaining == 0) { 
      continue; 
     } else if (remaining < MB_CUR_MAX) { 
      fseek(fd, -remaining, SEEK_CUR); 
     } else { 
      perror("Error"); 
      exit(1); 
     } 
    } 
} 

int main(int argc, char *argv[]) { 
    FILE *fd; 
    if (argc > 1) { 
     fd = fopen(argv[1], "rb"); 
    } else { 
     fd = fopen(DEFAULT_F_IN, "rb"); 
    } 

    setlocale(LC_ALL, ""); 
    struct counts c; 
    get_counts(&c, fd); 
    printf("chars: %d\tbytes: %d\n", c.chars, c.bytes); 

    return 0; 
} 
+3

'mbtowc()'返回-1,如果有一个不完整的多字节字符。 – caf 2012-02-10 02:46:00

+0

@caf哎呀。谢谢你的收获。尽管我现在已经纠正了它。 – Swiss 2012-02-10 03:03:46

+0

@瑞士此时,我已经_chars:16634_;但您的代码会引发分段错误 'while(bytes_read> 0){ \t \t \t n = mbtowc(NULL,p,MB_LEN_MAX); \t \t \t如果(N <= 0){ \t \t \t \t的p ++; \t \t \t \t bytes_read--; \t \t \t \t继续; \t \t \t} \t \t \t p + = n; \t \t \t \t \t \t bytes_read - = n; \t \t \t \t \t \t chars ++; \t \t}' – Figus 2012-02-10 03:09:49

相关问题