如何在C中获取以UTF-8编码的文本文件中的字符位置?

问题描述 投票:0回答:1

C 标准指定

ftell()
返回以二进制模式打开文件时从文件开头开始的字符位置。

...获取流的文件位置指示器的当前值 由流指向。对于二进制流,该值是来自的字符数 文件的开头。对于文本流,其文件位置指示符包含未指定的 信息,可由 fseek 函数用于返回文件位置指示符 流到 ftell 调用时的位置;两个这样的区别 返回值不一定是写入字符数的有意义的度量 或阅读。

如果文本文件具有宽字符,例如

ñ
,则
ñ
之后的任何字符的位置将大于文本文件中相应的列。具体来说,我在这里所说的位置是指,如果将文本文件读取为符号的线性序列,则对应的列。

例如,字符串

" ñ ñññ a ñ a"
有 12 个字符,但在此循环内打印
ftell()

void printPosition(FILE *file){
    
    int c;
    long i;
    while((c=fgetc(file)) != EOF){
        i = ftell(file);
        printf("%c %i\n", c, i);
    }
}

给出输出:

  1
├ 2
▒ 3
  4
├ 5
▒ 6
├ 7
▒ 8
├ 9
▒ 10
  11
a 12
  13
├ 14
▒ 15
  16
a 17

我尝试以文本/二进制读取模式打开,并得到相同的结果。

c file text utf-8 file-io
1个回答
0
投票

如果您的平台支持

UTF-8
兼容的语言环境,您可以使用宽字符逐字符读取文件。

#include <stdio.h>
#include <wchar.h>
#include <locale.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
int main() {
    {
        char *r = setlocale(LC_ALL, "C.UTF-8");
        if (!r) {
            perror("Could not setlocale to UTF-8");
            return EXIT_FAILURE;
        }
    }
    // Create a temporary file with the content.
    {
        const char str[] = " ñ ñññ a ñ a";
        FILE *f = fopen("/tmp/temp", "w");
        assert(f);
        int r = fwrite(str, 1, strlen(str), f);
        assert(r == strlen(str));
        r = fclose(f);
        assert(r == 0);
    }
    // Read the file
    {
        FILE *f = fopen("/tmp/temp", "r");
        assert(f);
        unsigned counter = 0;
        wint_t c;
        while ((c = fgetwc(f)) != WEOF) {
            printf("Character %lc at position %u\n", c, counter);
            counter++;
        }
        int r = fclose(f);
        assert(r == 0);
    }
}

执行程序会在 godbolt 上给出输出 https://godbolt.org/z/ojbK8MeEd :

Character   at position 0
Character ñ at position 1
Character   at position 2
Character ñ at position 3
Character ñ at position 4
Character ñ at position 5
Character   at position 6
Character a at position 7
Character   at position 8
Character ñ at position 9
Character   at position 10
Character a at position 11
© www.soinside.com 2019 - 2024. All rights reserved.