Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/34: Рейтинг темы: голосов - 34, средняя оценка - 4.56
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185

Позиция символа в UTF-8 строке

12.12.2014, 00:16. Показов 7407. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C++
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;
void main()
{
    // файл в UTF-8 без БОМ
    system("chcp 65001");
    char* s = "аБвгдеё1234567";
    // вывожу согласно обрезки по байтам
    // 2 буквы первых
    printf(((string)s).substr(0,4).c_str());
}
Как найти позицию буквы или проверить на признак начала / окончания русской 2ух-байтовой буквы ?
Ведь вся латиница и доп. символы по 1 байту.
Иероглиф японский вообще 3 байта.

Тобиж конкретнее если то мне надо прогнать по всей строке циклом и расставить метки позиций.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
12.12.2014, 00:16
Ответы с готовыми решениями:

Определить последнее вхождение символа “р” в строке и вывести строку, начиная с первого символа и до последнего “р” в строке
Заданы 2 строки, состоящие из слов, разделенных пробелами. Определить последнее вхождение символа “р” в строке и вывести строку, начиная с...

Замена символа в строке на число соответствующему номеру по порядку вхождения этого символа в строку
В заданной строке заменить каждый символ «*» числом, соответствующим номеру по порядку вхождения этого символа в строку.

Конвертация из ASCII в UTF-32 или UTF-8 в UTF-32
Собсно сабж.

16
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
12.12.2014, 00:43
Хранить/перекодировать файл в utf-16? Это куда меньший геморрой чем разбивать utf-8 на отдельные символы.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
12.12.2014, 00:52
Redee, здесь. От обычной индексации с целью получения символов придется отказаться. Длина строки тоже будет давать длину в байтах, а не в символах. По ссылке есть инструменты для удобной навигации по такой строке.
Методы find, compare и т.п. работают нормально.
Скажем, вот такой код отработает правильно, при условии что обе строки в UTF8:
C++
1
2
3
4
5
6
std::string str = "АБВГД";
size_t found = str.find("БВ");
if(found != std::string::npos)
{
    //в found индекс начала последовательности "БВ" в str
}
Добавлено через 2 минуты

Не по теме:

Цитата Сообщение от Renji Посмотреть сообщение
Хранить/перекодировать файл в utf-16?
Я ему это предлагал уже раза два в предыдущих темах. Целевая-то платформа Windows, логично, чтобы была родная кодировка.
Но ответных комментариев или каких-либо объяснений так и не дождался :)

1
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
12.12.2014, 07:41
Цитата Сообщение от Renji Посмотреть сообщение
Хранить/перекодировать файл в utf-16?
В чем разница? Тогда уж 32.
0
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
12.12.2014, 08:16
Вот мой недопиленый велосипед для подсчета кол-ва символов в utf-8
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <string>
// [url]https://ru.wikipedia.org/wiki/UTF-8[/url]
struct u8char {
    // 6 byte + \0 + length : data[data[7]] = '\0';
    char data[8];
};
unsigned char u8charlen(const char* s) {
    unsigned char len = 1;
    unsigned char bit = 1 << 7;
    if (0 != (*s & bit)) { // многобайтовый символ
        for (bit >>= 1; bit; bit >>= 1) {
            if (0 == (*s & bit))
                break;
            ++len;
        }
        if (1 == len) len = 0; // не первый байт
        else
            ;// тут надо проверить len следующих байт: mask = 2 << 6;  (*s & mask) == mask;
    }
    else
        ; // ASCII символ
    return (len > 6) ? 0 : len;
}
size_t u8strlen(const char* s) {
    size_t len = 0;
    if (s) {
        while (*s) {
            unsigned sub = u8charlen(s);
            if (0 == sub) break;
            s += sub;
            ++len;
        }
    }
    return len;
}
int main() {
    const char word[] = u8"Слово";
    printf("length = %u", u8strlen(word));
    return 0;
}
0
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
12.12.2014, 13:36
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
В чем разница? Тогда уж 32.
В фиксированности размера символа.
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
12.12.2014, 13:38
Цитата Сообщение от Renji Посмотреть сообщение
В фиксированности размера символа.
Ну по-хорошему она и в UTF-16 не фиксированная. Фиксированная она в UCS-2.
Другое дело, что на большинстве языков автор этого просто не заметит.
0
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
12.12.2014, 13:45
Цитата Сообщение от Renji Посмотреть сообщение
В фиксированности размера символа.
Нет ее там.
0
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
12.12.2014, 21:43  [ТС]
Давайте еще проще.
Строка / буфер, консоль в utf-8, их нельзя менять в другую кодировку под страхом "расстрела на месте".
Задача - Гарантировано вывести символ равный его порядковому номеру в строке.

Выведи мне 3ий символ - получаю 3ий символ, при этом библиотека знает все признаки символов.
А не так - выведи мне 3ий символ, хорошо выведу относительно позиции байта, а попало это на начало или в середине диапазона признака символа Проблемы уже Ваши.

Да вы скажете блин зачем парить конторы вгоняю в кодировку 866 / 1251 там вся латиница с кирилицей по 1 байту и подсчитать и вывести нет ничего сложного, ну почти нет )).

Посмотрю алгоритм Cra3y.
Знаете недавно ища ответ на этот вопрос, натолкнулся на одну зарубежную статью про эти признаки, но решение показалось настолько Громоздким и Ужасным, что я в панике закрыл ту страницу.
Неужели нет достойных простых решений.
И это согласитесь не тот случай "нельзя вот так просто взять и..."
Да блин НЕТ ЖЕ оно должно быть ПРОСТО.

Ну это лишь мое видиние, или не видиние вопроса.

Еще насчет перекодировки, почему я эту затею вообще начал.
Замечательная библиотека libiconv прекрасно справляется со своей задачей.
Но вот тут большое НО, так как она оперирует с исходным массивом на char, замечу не путать с char*.

У меня там стоит буфер на char[100] к примеру.
Скармливать я должен со строки UTF-8 опять же к примеру.
Если так прикинуть если даже по 4 байта которые максимум оно может принять (utf-8 1 символ) - получается по 25 символов.
Там могут быть теже иероглифы по 3 байта и опять же я НЕ уверен в точной позиции иероглифа.
25(100) гарантированных символов/байтов отдал, но НЕТ никакой уверенности нахожусь после 100 отданных байт вначале нового символа или прямо "в нем".

Ну блин вы же тоже сталкивались с этой "проблемой".
Конечно проблем нет когда символы максимум по 1 байт (866/1251).
В utf-8 гарантировано лишь в том случае если работаем лишь с ASCII символами.

Получилось громоздко, но хотел донести основную суть.
0
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
12.12.2014, 22:03  [ТС]
Если интересно >>
Конечно коряво и НЕ доработано, но частично справляется.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include "iconv.h"
using namespace std;
 
// кодировка файла UTF-8, преобразовывает в cp1251
void utf8ToCp1251(char* src)
{
    const int bufSize = 100;
    char buf[bufSize];
    strcpy_s(buf, src);
 
    const char* srcPt = buf;
    const size_t srcLenBase = bufSize;
 
    size_t srcLen = srcLenBase;
    // размер тот же если конечная кодировка меньше байтов на символ выделяет
    const size_t dstLenBase = srcLenBase;
    //const size_t dstLenBase = srcLenBase *2;
    size_t dstLen = dstLenBase;
 
    char dst[dstLenBase];
    char* dstPt = dst;
    
    iconv_t conv = iconv_open("CP1251","UTF-8");
    iconv(conv, &srcPt, &srcLen, &dstPt, &dstLen);
    iconv_close(conv);
 
    system("chcp 1251");
    printf(dst);
    cout << endl;
}
 
 
void main()
{
    // наша песня хороша но строка должна быть НЕ больше буфера
    // в позиции буквы относительно порядкового номера в строке НЕ уверены
    char* s = "фываЁё321sdfвыа";
    utf8ToCp1251(s);
}
Вложения
Тип файла: zip testCP.zip (651.8 Кб, 3 просмотров)
0
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
12.12.2014, 22:11  [ТС]
На той же википедии хорошо основу UTF8 объясняют.
https://ru.wikipedia.org/wiki/UTF-8
Но ни бум бум как говорится...
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
12.12.2014, 22:18
Цитата Сообщение от Redee Посмотреть сообщение
Неужели нет достойных простых решений.
Ну я же тебе дал ссылку на библиотеку, она header-only. Там есть итераторы для utf8 символов. Методы получения длины строки, следующего символа, предыдущего символа и много чего еще. Ну потрать ты 5 минут, чтобы разобраться
1
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
12.12.2014, 22:43  [ТС]
Ага вчера втыкал именно эту статью, до меня как до жирафа знаешь ли, но если пойму то надолго ).

Добавлено через 10 минут
Качнул отсельда, будем внедрять.
http://sourceforge.net/projects/utfcpp/
До конца недели надеюсь справлюсь.

Добавлено через 6 минут
Их там окромя utf8.h еще и checked.h / core.h / unchecked.h
Дуплим, дуплим.

Добавлено через 5 минут
Цитата Сообщение от Renji Посмотреть сообщение
Хранить/перекодировать файл в utf-16? Это куда меньший геморрой чем разбивать utf-8 на отдельные символы.
При перекодировки utf-8 мы же должны быть уверены в позиции символов (передаем частями конвертеру).
Вот такое решение и прилетает на помощь, на которое еще раз указал DrOffset.
http://utfcpp.sourceforge.net/
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
12.12.2014, 23:41
Цитата Сообщение от Redee Посмотреть сообщение
Ага вчера втыкал именно эту статью, до меня как до жирафа знаешь ли, но если пойму то надолго ).
Да там ничего особо сложного. Вот смотри:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <string>
#include <cstdio>
#include <windows.h>
 
#include "utf8.h" 
 
int main()
{
// консолька в режиме UTF8
    ::SetConsoleOutputCP(CP_UTF8);
 
// кодировка исходника UTF8 без BOM
    std::string s = "АБВГД"; 
 
    typedef utf8::iterator<std::string::iterator> utf8_string_iterator;
 
    utf8_string_iterator it(s.begin(), s.begin(), s.end());
    for(; it.base() != s.end(); ++it) // итерируемся именно по символам. 
    // Фасад utf8 итератора надстроен над обычными итераторами строки
    {
        uint32_t code = *it; // *it возвращает собранные вместе юниты utf8. По сути это utf32
        // его можно сравнивать с другими в таком виде одним махом, как символ.
 
        // Для того чтобы вывести в консоль в режиме UTF8, нужно код преобразовать в обычный строковый вид, 
        // для этого есть функция append
        char buf[7] = {}; //буфер для "символа", максимум 6 юнитов + 1 для завершающего нуля
        utf8::append(code, buf);
 
        printf("[%s]", buf); // вывод на экран "символа" utf8
    }
    printf("\n"); 
}
1
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
13.12.2014, 00:23  [ТС]
А если так все же ?)
Строка str = "фЫdz7"
> Запрос - дай мне байты до 3го символа, ответ - кол-во байт до 3го символа = 5.
Как это вытворить?
Теперь я спокойно побайтово обрезаю зная точно что это конец буквы а НЕ середина символа.
Тобиж в этом случае какая реализация?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
13.12.2014, 00:30
Лучший ответ Сообщение было отмечено Redee как решение

Решение

Цитата Сообщение от Redee Посмотреть сообщение
Запрос - дай мне байты до 3го символа, ответ - кол-во байт до 3го символа = 5.
C++
1
2
3
4
5
6
    std::string s = "фЫdz7"; 
    std::string::iterator st = s.begin();
 
    utf8::advance(st, 3, s.end());
 
    printf("Количество байт до третьего символа: %d\n", std::distance(s.begin(), st));
Добавлено через 52 секунды
Redee, на всякий случай имей в виду, что checked версия utf8:: бросается исключениями, если что-то не так.
1
31 / 40 / 6
Регистрация: 04.10.2014
Сообщений: 185
13.12.2014, 01:10  [ТС]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include "utf8.h"
using namespace std;
using namespace utf8;
 
void main()
{
    system("chcp 65001");
    string str = "ыЭsd5678";
 
    string::iterator itBeg = str.begin();
    string::iterator itEnd = str.end();
 
    int len = utf8::distance(itBeg, itEnd);
    // вывело верно 8 символов
    cout << len << endl;
}
Получается то что оно "возможно" знает о байтах символа также, если посчитало верное кол-во utf-8 символов.

Добавлено через 52 секунды
Ооо спасибо, ща затещу.

Добавлено через 2 минуты
Круто, круто!
Действительно мощный прием.

Добавлено через 8 минут
Очень выгодное взаимное использование utf8::distance(...) - по символам счет
std::distance(...) - по байтам
При этом итераторы точно указывают на позицию с помощью utf8::advance(...), который меняет текущую позицию итератора.

Добавлено через 12 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include "utf8.h"
using namespace std;
using namespace utf8;
 
void main()
{
    system("chcp 65001");
    string str = "ыЭsd5678";
 
    string::iterator itBeg = str.begin();
    string::iterator itEnd = str.end();
    string::iterator iTer = itBeg;
 
    int len = utf8::distance(itBeg, itEnd);
    // вывело верно 8 символов
    cout << len << endl;
    // все верно побайтово = 10 байт
    cout << std::distance(itBeg, itEnd) << endl;
 
    // вывел сколько байт с 3го до конца строки (сдвинул на 2 символа)
    // все верно 6 байт
    utf8::advance(iTer, 2, itEnd);
    cout << std::distance(iTer, itEnd);
}
Добавлено через 11 минут
Потестировал на японских / тайских символах.
Все нормально также )).
Да есть жеж.

Добавлено через 2 минуты
Огромное спасибо DrOffset-у.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.12.2014, 01:10
Помогаю со студенческими работами здесь

В строке заменить каждый символ «!» числом, равным индексу этого символа в строке
В заданной строке заменить каждый символ «!» числом, равным индексу этого символа в строке. Сделал просто замену символа на любой ...

поиск в win1251 строке работает, а в UTF-8 - нет
Есть код: ....... URLDownloadToFile(0, urlfile1.c_str(), L&quot;SAVENAME1&quot;,0,0); filenam = &quot;SAVENAME1&quot;; .................. ...

Позиция элемента в контейнере STL кон. SET, поиск контейнер set словарь позиция
Есть код №1. Он выводить на экран позицию нужного мне слова (только если в середине 1 слово а не 2 и больше например только...

Поиск символа в строке
Здравствуйте! у меня такой вопрос, надо найти символ в строке, а именно символ '&lt;' и '&gt;' между этими символами может быть что...

Замена символа в строке
Доброго времени суток. Помогите разобраться с ошибкой. 2 IntelliSense: отсутствуют экземпляры перегруженная функция...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru