Как посчитать количество многобайтовых символов? - PullRequest
0 голосов
/ 08 февраля 2019

Я бы хотел получить 5 вместо 10 для следующей программы.Кто-нибудь знает, как исправить код для подсчета количества многобайтовых символов?Спасибо.

/* vim: set noexpandtab tabstop=2 shiftwidth=2 softtabstop=-1 fileencoding=utf-8: */
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

size_t nchars(const char *s) {   
    size_t charlen, chars;
    mbstate_t mbs;

    chars = 0;
    memset(&mbs, 0, sizeof(mbs));
    while (
            (charlen = mbrlen(s, MB_CUR_MAX, &mbs)) != 0
            && charlen != (size_t)-1
            && charlen != (size_t)-2
            ) {
        s += charlen;
        chars++;
    }   

    return (chars);
}   

int main() {
    setlocale(LC_CTYPE, "en_US.utf8");
    char * text = "öçşğü";

    printf("%zu\n", nchars (text));

    return 0;
}
$ ./main.exe 
10

1 Ответ

0 голосов
/ 08 февраля 2019

Вторичная проблема: вы должны инициализировать объект типа mbstate_t с помощью функции mbsinit, а не memcpy.Полностью байтов ноль mbsinit не гарантируется как начальное состояние сдвига, так и даже любое допустимое состояние сдвига.

Основная проблема с вашим кодом заключается в том, что он анализирует строковый литерал,чье представление определяется во время компиляции на основе фактической кодировки этих символов в исходном файле, их представления в исходном наборе символов компилятора и набора символов выполнения, выбранного компилятором.Вы не можете выбрать LC_CTYPE произвольно - его нужно сопоставить с данными, чтобы функции преобразования в mb работали, как предполагалось.

C не определяет механизм, позволяющий программе определить языковой стандарт, для которого LC_TYPEсоответствует набору символов выполнения и даже не требует наличия такой локали.Документация вашего компилятора должна описывать сопоставление между исходными символами и исполняющими символами, однако, возможно, с точки зрения локали или хорошо известной кодировки, и она может даже описывать способ указать это.В документации вашего компилятора также может быть описан способ указать кодировку, которую он должен принимать для исходных файлов.

Кроме того, , у вас есть дополнительная потенциальная проблема с Unicode, что может быть несоответствие междучто вы, человек, считаете «персонажем» и символами Юникода, которыми он представлен.Как правило, это касается символов с диакритическими знаками, таких как акценты.Многие из наиболее часто используемых из них имеют односимвольное «составное» представление, но также могут быть представлены в виде последовательности базового символа плюс один или несколько комбинирующих символов.

mbrlen() вряд лиразличайте базовые и комбинирующие символы, поэтому даже без путаницы в кодировке ваш наблюдаемый результат может быть результатом того, что символы представлены в разложенном виде в исходных файлах или преобразованы в эту форму компилятором.

ВнизуСуть в том, что ваша программа зависит от характеристик среды и реализации, которые не указаны в стандарте, поэтому она может вести себя по-разному в разных реализациях, что, по-видимому, и является наблюдением.Ваше конкретное наблюдение может возникнуть, например, из исходного файла, кодируемого в UTF-8, компилятор предполагает, что он будет закодирован в однобайтовой кодировке, такой как ISO-8859-1, а компилятор использует UTF-8.для его набора символов выполнения.

Ваш подход может работать без изменений, если вы убедитесь, что компилятор интерпретирует исходный файл в соответствии с фактической кодировкой этого файла и использует UTF-8 в качестве набора символов выполнения.В качестве альтернативы, в C11 или позже вы можете гарантировать , что кодирование этой конкретной строки во время выполнения - это UTF-8 с использованием литерала UTF-8, например, так:

char * text = u8"öçşğü";

Это заботитсятолько кодирования на стороне исполнения, однако.Вам все еще нужно сопоставить кодировку исходного файла с фактической кодировкой, ожидаемой компилятором, и вы по-прежнему можете зависеть от различий между предварительно составленными и разложенными символами.

...