Как игнорировать акценты в строке, чтобы она не меняла свою длину?

Я определяю длину определенных строк символов в C++ с помощью функции length(), но заметил одну странность: допустим, я определяю в функции main

string str;
str = "canción";

Затем, когда я вычисляю длину str на str.length(), я получаю результат 8. Если вместо этого я определяю str = "cancion" и снова вычисляю длину str, результатом будет 7. Другими словами, ударение на букву «о» изменяет реальную длину строки. То же самое происходит и с другими акцентами. Например, если str = "für", он скажет мне, что его длина равна 4 вместо 3.

Я хотел бы знать, как игнорировать эти акцентированные символы при определении длины строки; однако я бы не хотел игнорировать отдельные символы, такие как '. Например, если str = livin', длина str должна быть 6.


person Carl Rojas    schedule 24.11.2015    source источник
comment
если вы используете окна, используйте wstring. Я говорю только для окон из-за этого   -  person R Nar    schedule 24.11.2015
comment
Вы получаете дополнительный символ не потому, что строка содержит o' или что-то в этом роде, а потому, что символ Юникода ó состоит из двух байтов.   -  person Baum mit Augen    schedule 24.11.2015
comment
Добро пожаловать в грустное слово о кодировании текста в исходных литералах, кодировании текста в целом, кодировании переменной длины в частности и, возможно, нормализации юникода, если вы чувствуете себя достаточно сильным. Прежде всего, вы должны указать кодировку, которую вы используете для текста в вашем приложении, для ваших исходных файлов и как ваш компилятор настроен в этом отношении. Кроме того, поскольку в стандарте C++ сильно не хватает информации о кодировках, может быть полезно знать, какой компилятор вы используете на какой платформе.   -  person Matteo Italia    schedule 24.11.2015
comment
Похоже, вы используете кодировку UTF-8, но было бы лучше, если бы это было указано в самом вопросе. В противном случае ответы будут содержать догадки, которые могут оказаться бесполезными для будущих читателей.   -  person MrEricSir    schedule 24.11.2015
comment
@MrEricSir извините за мое невежество, но как мне узнать, какую кодировку я использую?   -  person Carl Rojas    schedule 24.11.2015
comment
Зачем вам длина в символах? Что такое является персонажем?   -  person n. 1.8e9-where's-my-share m.    schedule 08.08.2018
comment
Вам нужна длина, равная количеству столбцов в терминале? Потому что если это так, вам также нужно беспокоиться о многоколоночных символах — см. \uff20 и большинство азиатских символов. И даже тогда не все терминалы используют одну и ту же версию стандарта...   -  person o11c    schedule 08.08.2018
comment
Карл, там не текст, а закодированный текст. Как узнать, какую [какую символьную] кодировку я использую? Есть много контекстов, где это важно. Во-первых, вы выбираете, когда вы сохраняете исходный файл. Затем вы должны сообщить об этом своему компилятору. Каждая передача текста включает в себя байты и кодировку. Но что говорит @n.m. Пожалуйста, отредактируйте свой вопрос.   -  person Tom Blodget    schedule 08.08.2018


Ответы (2)


Это сложная тема. Ваша строка, вероятно, закодирована в кодировке UTF-8, и str.length() подсчитывает байты. Символ ASCII может быть закодирован в 1 байт, но символы с кодами больше 127 кодируются более чем в 1 байт.

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

Вы можете проверить ICU.

Если у вас ограниченный случай и вы не хотите использовать для этого библиотеку, вы можете проверить кодировка UTF-8 (это несложно) и создайте простой счетчик кодовых точек UTF-8 (простой алгоритм может заключаться в подсчете байтов, где (b&0xc0)!=0x80).

person geza    schedule 07.08.2018
comment
Сначала вам нужно нормализовать строку. Не забывайте, что не все комбинации букв и диакритических знаков имеют заранее составленные формы, поэтому нормализация не обязательно поможет. И когда вы принимаете во внимание ширину символов, я думаю, что нормализация больше не имеет значения: объединение символов должно рассматриваться как имеющее ширину 0. - person ; 08.08.2018
comment
@hvd: абсолютно верное замечание, я немного изменил свой ответ. - person geza; 08.08.2018
comment
ICU известен тем, что является раздражающей библиотекой для использования, w.r.t. версии... одной из моих долгосрочных целей является написать библиотеку, в которой вам нужно всего лишь изменить файл data, чтобы обновить версию стандарта Unicode, который вы используете - person o11c; 08.08.2018
comment
@ o11c: возможно, это возможно, только если в этих данных есть сценарии. - person geza; 08.08.2018

Похоже на кодировку UTF-8. Поскольку символы с диакритическими знаками нельзя хранить в одном байте, они хранятся в двух байтах. См. https://en.wikipedia.org/wiki/UTF-8.

person DBug    schedule 24.11.2015