Кроссплатформенная работа со строками.
От: WerWoolf  
Дата: 30.06.15 19:26
Оценка:
Здравствуйте. В связи с работой над одним проектом, возник вопрос в реализации класса строки.
Реализация должна быть кроссплатформенной. Необходима поддержка всех доступных языков,
т.е. ascii не подходит. Задача данного вопроса — узнать возможные варианты реализации
класса, их плюсы и минусы.

Варианты решения:

1) Класс-обертка, который хранит строку как последовательность wchar_t символов.
Здесь хотелось бы узнать плюсы или минусы данного варианта.

2) Класс-обертка, который хранит строку как последовательность char символов, но в
кодировке utf-8. Реализовать конвертеры в другие кодировки.
Здесь хотелось бы узнать плюсы или минусы данного варианта.

3) Другой вариант (который вы считаете лучшим).

Я не прошу вас реализовывать данный класс, просто хотелось бы систематизировать данные
по этому вопросу. Надеюсь на конструктивные ответы.
Всем спасибо.

P.S. Пожалуйста, не предлагайте использовать уже существующие классы из сторонних библиотек,
такие как QString и т.п.
Отредактировано 30.06.2015 19:28 WerWoolf . Предыдущая версия .
c++ c++11 string
Re: Зачем?
От: omgOnoz  
Дата: 30.06.15 19:31
Оценка:
Здравствуйте, WerWoolf, Вы писали:

  Скрытый текст
WW>Здравствуйте. В связи с работой над одним проектом, возник вопрос в реализации класса строки.
WW>Реализация должна быть кроссплатформенной. Необходима поддержка всех доступных языков,
WW>т.е. ascii не подходит. Задача данного вопроса — узнать возможные варианты реализации
WW>класса, их плюсы и минусы.

WW>Варианты решения:


WW>1) Класс-обертка, который хранит строку как последовательность wchar_t символов.

WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>2) Класс-обертка, который хранит строку как последовательность char символов, но в

WW>кодировке utf-8. Реализовать конвертеры в другие кодировки.
WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>3) Другой вариант (который вы считаете лучшим).


WW>Я не прошу вас реализовывать данный класс, просто хотелось бы систематизировать данные

WW>по этому вопросу. Надеюсь на конструктивные ответы.
WW>Всем спасибо.

WW>P.S. Пожалуйста, не предлагайте использовать уже существующие классы из сторонних библиотек,

WW>такие как QString и т.п.


Есть std::string + куча наворотов в последних стандартах. Есть QT QString — со своими наворотами.
Re[2]: Зачем?
От: WerWoolf  
Дата: 30.06.15 19:35
Оценка:
Здравствуйте, omgOnoz, Вы писали:

O>Есть std::string + куча наворотов в последних стандартах. Есть QT QString — со своими наворотами.


Ну я бы не сказал что их куча.
1) есть строковые литералы типа: u8, u, U для кодировок UTF
2) есть конвертеры std::codecvt и наследники.

Больше ничего на ум не приходит.
Отредактировано 30.06.2015 19:35 WerWoolf . Предыдущая версия .
Re[3]: Зачем?
От: omgOnoz  
Дата: 30.06.15 19:43
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>Ну я бы не сказал что их куча.

WW>1) есть строковые литералы типа: u8, u, U для кодировок UTF
WW>2) есть конвертеры std::codecvt и наследники.

WW>Больше ничего на ум не приходит.


Смотри QString.

Просто задач, где нужна конвертация в другую кодировку — ... не знаю.

Я привык, что по умолчанию, весь текст в UTF-8
Отредактировано 30.06.2015 19:45 omgOnoz . Предыдущая версия . Еще …
Отредактировано 30.06.2015 19:43 omgOnoz . Предыдущая версия .
Re[2]: Зачем?
От: MTD https://github.com/mtrempoltsev
Дата: 30.06.15 19:46
Оценка:
Здравствуйте, omgOnoz, Вы писали:

O>Есть std::string + куча наворотов в последних стандартах.


Это немногим лучше vector<char>. В С++ фактически нет поддержки строк, поэтому надо это принять и использовать ICU.
Re[4]: Зачем?
От: WerWoolf  
Дата: 30.06.15 19:49
Оценка:
Здравствуйте, omgOnoz, Вы писали:

O>Просто задач, где нужна конвертация в другую кодировку — ... не знаю.


O>Я привык, что по умолчанию, весь текст в UTF-8


Ну да, по задаче мне тоже конвертация не часто нужна.
Просто тут могут быть проблемы: допустим я использую std::string, и он отлично будет работать
для одно байтовых кодировок.
Пример:

std::string str1 = u8"abc";
std::string str2 = u8"абв";

str1.length() = ?
str2.length() = ?

могу предположить, что они не будут одинаковы.
Отредактировано 01.07.2015 8:15 WerWoolf . Предыдущая версия .
Re: Кроссплатформенная работа со строками.
От: MTD https://github.com/mtrempoltsev
Дата: 30.06.15 19:49
Оценка: +1
Здравствуйте, WerWoolf, Вы писали:

WW>Здравствуйте. В связи с работой над одним проектом, возник вопрос в реализации класса строки.


Если тебе от строки нужен только контейнер, то храни все в std::string в utf-8. Если тебе нужно итерировать по буквам, делать некие преобразования и т.д., то сам ты писать умаешься — посмотри ICU, чтобы оценить объем работы.
Re[5]: Зачем?
От: omgOnoz  
Дата: 30.06.15 19:53
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>Ну да, по задаче мне тоже конвертация не часто нужна.

WW>Просто тут могут быть проблемы: допустим я использую std::string, и он отлично будет работать
WW>для одно байтовых кодировок.
WW>Пример:

WW>std::string str1 = u"abc";

WW>std::string str2 = u"абв";

WW>str1.length() = ?

WW>str2.length() = ?

WW>могу предположить, что они не будут одинаковы.


Да эта проблема не решаема с помощью стандартной библиотеки. Смотри ниже.
Re: Кроссплатформенная работа со строками.
От: WerWoolf  
Дата: 30.06.15 19:59
Оценка:
Использование сторонних библиотек, особенно тяжеловесных, не желательно.
Может есть что-нибудь легковесное, и с бесплатной лицензией. Чтобы его можно
было переделать и внедрить в свой проект?
Re[2]: Кроссплатформенная работа со строками.
От: omgOnoz  
Дата: 30.06.15 20:06
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>Использование сторонних библиотек, особенно тяжеловесных, не желательно.

WW>Может есть что-нибудь легковесное, и с бесплатной лицензией. Чтобы его можно
WW>было переделать и внедрить в свой проект?

ICU можно использовать, как отдельную-системную библиотеку.

Но на венде выглядит так, что каждый тянет с собой свою копию библиотеке. На линуксе тоже свои приколы.
Отредактировано 30.06.2015 20:15 omgOnoz . Предыдущая версия . Еще …
Отредактировано 30.06.2015 20:09 omgOnoz . Предыдущая версия .
Отредактировано 30.06.2015 20:08 omgOnoz . Предыдущая версия .
Re[5]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 20:23
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>std::string str1 = u"abc";

WW>std::string str2 = u"абв";

WW>str1.length() = ?

WW>str2.length() = ?

WW>могу предположить, что они не будут одинаковы.


А точно будут ситуации, когда это важно? Ещё надо помнить, что в юникоде длина строки в байтах, code points, буквах и глифах может быть четырьмя различными числами.
Ce n'est que pour vous dire ce que je vous dis.
Re[6]: Зачем?
От: WerWoolf  
Дата: 30.06.15 20:36
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>А точно будут ситуации, когда это важно?


В принципе да, такие ситуации будут.
Такие базовые вещи, как поиск подстроки, замена и др., как мне кажется могут
потребовать длину строки в в символах.
Re[7]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 20:38
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>В принципе да, такие ситуации будут.

WW>Такие базовые вещи, как поиск подстроки, замена и др., как мне кажется могут
WW>потребовать длину строки в в символах.

Тогда присоединяюсь к рекомендующим ICU.
Ce n'est que pour vous dire ce que je vous dis.
Re[8]: Зачем?
От: WerWoolf  
Дата: 30.06.15 20:43
Оценка:
А чем плох вариант всюду использовать wchar_t?
Стандарт, насколько мне известно, гарантирует, что один wchar_t должен соответствовать одному символу.
Отредактировано 30.06.2015 20:49 WerWoolf . Предыдущая версия .
Re[9]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 20:51
Оценка: +1
Здравствуйте, WerWoolf, Вы писали:

WW>А чем плох вариант всюду использовать wchar_t?

WW>Стандарт насколько мне известно гарантирует, что один wchar_t должен соответствовать одному символу.

Под Windows wchar_t 16 байтов, чего не достаточно для покрытия всего юникода. Плюс, один символ может быть выражен последовательностью юникодовых значений. Более того, один и тот же символ может быть выражен различными последовательностями. С текстом сложно правильно работать.
Ce n'est que pour vous dire ce que je vous dis.
Re[10]: Зачем?
От: Went  
Дата: 30.06.15 21:05
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>Под Windows wchar_t 16 байтов, чего не достаточно для покрытия всего юникода. Плюс, один символ может быть выражен последовательностью юникодовых значений. Более того, один и тот же символ может быть выражен различными последовательностями. С текстом сложно правильно работать.

Разве 32-битный wchar не гарантирует полного покрытия всех словарей? Что мешает определить свой std::string для полного слова?
Re[11]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 21:11
Оценка:
Здравствуйте, Went, Вы писали:

W>Разве 32-битный wchar не гарантирует полного покрытия всех словарей? Что мешает определить свой std::string для полного слова?


Можно определить свой basic_string<uint32_t>, но это не отменяет существования combining character sequences.
Ce n'est que pour vous dire ce que je vous dis.
Re[12]: Зачем?
От: Went  
Дата: 30.06.15 21:34
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>Можно определить свой basic_string<uint32_t>, но это не отменяет существования combining character sequences.

В википедии пишут, что на UTF-32 такие фокусы не распространяются. Врут?
Re[13]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 21:38
Оценка:
Здравствуйте, Went, Вы писали:

DR>>Можно определить свой basic_string<uint32_t>, но это не отменяет существования combining character sequences.


W>В википедии пишут, что на UTF-32 такие фокусы не распространяются. Врут?


UTF32 — это о кодировке и не имеет отношения к combining character sequences.

UTF-32 does not make calculating the displayed width of a string easier, since even with a “fixed width” font there may be more than one code point per character position (combining marks) or more than one character position per code point (for example CJK ideographs).

https://en.wikipedia.org/wiki/UTF-32
Ce n'est que pour vous dire ce que je vous dis.
Re[14]: Зачем?
От: Went  
Дата: 30.06.15 21:52
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>UTF32 — это о кодировке и не имеет отношения к combining character sequences.

DR>https://en.wikipedia.org/wiki/UTF-32
А, то есть некоторые символы могут быть записаны последовательностями 32-битных чаров, но для них, как правило, существует одночаровый эквивалент (кроме самых экзотических случаев)?
Re[15]: Зачем?
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 30.06.15 22:02
Оценка: 2 (1)
Здравствуйте, Went, Вы писали:

W>А, то есть некоторые символы могут быть записаны последовательностями 32-битных чаров, но для них, как правило, существует одночаровый эквивалент (кроме самых экзотических случаев)?


Можно и так сказать. ICU умеет приводить различные варианты записи таких символов к одному варианту когда это возможно.

http://userguide.icu-project.org/transforms/normalization
Ce n'est que pour vous dire ce que je vous dis.
Re: Кроссплатформенная работа со строками.
От: saf_e  
Дата: 02.07.15 07:35
Оценка: +2
Здравствуйте, WerWoolf, Вы писали:

WW>Здравствуйте. В связи с работой над одним проектом, возник вопрос в реализации класса строки.

WW>Реализация должна быть кроссплатформенной. Необходима поддержка всех доступных языков,
WW>т.е. ascii не подходит. Задача данного вопроса — узнать возможные варианты реализации
WW>класса, их плюсы и минусы.

WW>Варианты решения:


WW>1) Класс-обертка, который хранит строку как последовательность wchar_t символов.

WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>2) Класс-обертка, который хранит строку как последовательность char символов, но в

WW>кодировке utf-8. Реализовать конвертеры в другие кодировки.
WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>3) Другой вариант (который вы считаете лучшим).


WW>Я не прошу вас реализовывать данный класс, просто хотелось бы систематизировать данные

WW>по этому вопросу. Надеюсь на конструктивные ответы.
WW>Всем спасибо.

WW>P.S. Пожалуйста, не предлагайте использовать уже существующие классы из сторонних библиотек,

WW>такие как QString и т.п.

И std::string и std::wstring кросс-платформены и могут хранить любые символы до тех пор пока вы их интерпретируете как UTF-8 и UTF-16.
Обычно внутри программы (системы) имеет смысл принять один из вышеперечисленных и и спользовать его. А вовне отдавать конвертируя в нативное представление.

На Виндах нативное обычно UTF-16, в прочих больше прижилось UTF-8. Самый головняк, что стандартная библиотека MSVC поддерживает UTF-16, но UTF-8 не понимает считая его ANSI, а в остальных банально нету во многих местах поддржки UTF-16 (типа открыть файл/стрим). Это если конечно ниче не поменялось.

Поэтому пока у вас задача только хранить (и неизвестно надо ли еще чего-то) выберите кодировку и успокойтесь. Как надо будет что-то еще — ICU обычно хорошее решение, но часто можно обойтись и системным API.
Re[2]: Кроссплатформенная работа со строками.
От: uzhas Ниоткуда  
Дата: 02.07.15 08:18
Оценка:
Здравствуйте, saf_e, Вы писали:

_>И std::string и std::wstring кросс-платформены


все же std::wstring я бы не назвал кроссплатформенным из-за разного размера wchar_t у VS и gcc. в частности, на линуксе std::wstring часто интерпретируется, как UTF-32, а на винде, как UTF-16 (или как UCS-2)
по теме: многое зависит от сценариев использования. универсальных строк нет, у всех есть свои преимущества и недостатки.
лично я по дефолту использую basic_string, т.к. это стандартно (нет внешних зависимостей) и минимум накладных расходов; и пишу я обычно серверный софт (пусть даже и локализованный). использовать в юникодном гуе icu или другие жирные строки считаю нормальным ибо в гуе обычно перформанс не так важен, а корректность работы с разными языками важнее.
Re[3]: Кроссплатформенная работа со строками.
От: WerWoolf  
Дата: 02.07.15 08:36
Оценка:
Тут кто-то выше по теме обмолвился, что code point и символ не имеют однозначного соответствия.
Может кто-нибудь пояснит, почему так?
Re[3]: Кроссплатформенная работа со строками.
От: saf_e  
Дата: 02.07.15 08:39
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, saf_e, Вы писали:


_>>И std::string и std::wstring кросс-платформены


U>все же std::wstring я бы не назвал кроссплатформенным из-за разного размера wchar_t у VS и gcc. в частности, на линуксе std::wstring часто интерпретируется, как UTF-32, а на винде, как UTF-16 (или как UCS-2)

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

на счет std::wstring согласен, этот нюанс нужно учесть при сериализации, как только они в памяти дальше разницы нет.
Re[4]: Кроссплатформенная работа со строками.
От: WerWoolf  
Дата: 06.07.15 19:53
Оценка:
Решил не создавать еще одну тему для этого вопроса.

#include <iostream>

int main()
{
    std::cout << u8"это строка6" << std::endl;
    return 0;
}


Устанавливаю в консоли кодовую страницу с помощью следующей команды:
chcp 65001

Выполняю программу, и получаю следующий вывод:
��то строка6


Почему первый символ отобразился неправильно?
Re[5]: Кроссплатформенная работа со строками.
От: VTT http://vtt.to
Дата: 06.07.15 21:16
Оценка: +1
а там случаем BOM не добавляется в начало строки?
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[6]: Кроссплатформенная работа со строками.
От: WerWoolf  
Дата: 07.07.15 07:40
Оценка:
Здравствуйте, VTT, Вы писали:

VTT>а там случаем BOM не добавляется в начало строки?


Ну, судя по выводу, при использовании литерала u8, BOM в начало не добавляется.
Это кодировка 65001 думает, что в начале идет BOM, пытается прочитать его,
а остальное выводит нормально. Тогда хотелось бы найти кодировку UTF-8 без BOM.
Re[9]: Зачем?
От: MasterZiv СССР  
Дата: 07.07.15 08:00
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>А чем плох вариант всюду использовать wchar_t?

WW>Стандарт, насколько мне известно, гарантирует, что один wchar_t должен соответствовать одному символу.

Нет, не гарантирует.
Это гарантируется только для языков кроме китайского. Подробнее смотри в стандарте Unicode.
Re: Кроссплатформенная работа со строками.
От: ZiloT  
Дата: 21.07.15 12:16
Оценка: 8 (1)
Здравствуйте, WerWoolf, Вы писали:

WW>Здравствуйте. В связи с работой над одним проектом, возник вопрос в реализации класса строки.

WW>Реализация должна быть кроссплатформенной. Необходима поддержка всех доступных языков,
WW>т.е. ascii не подходит. Задача данного вопроса — узнать возможные варианты реализации
WW>класса, их плюсы и минусы.

WW>Варианты решения:


WW>1) Класс-обертка, который хранит строку как последовательность wchar_t символов.

WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>2) Класс-обертка, который хранит строку как последовательность char символов, но в

WW>кодировке utf-8. Реализовать конвертеры в другие кодировки.
WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

WW>3) Другой вариант (который вы считаете лучшим).


WW>Я не прошу вас реализовывать данный класс, просто хотелось бы систематизировать данные

WW>по этому вопросу. Надеюсь на конструктивные ответы.
WW>Всем спасибо.

WW>P.S. Пожалуйста, не предлагайте использовать уже существующие классы из сторонних библиотек,

WW>такие как QString и т.п.

Рекомендую к прочтению utf8everywhere
Re: Кроссплатформенная работа со строками.
От: drVanо Россия https://vmpsoft.com
Дата: 26.07.15 18:37
Оценка:
Здравствуйте, WerWoolf, Вы писали:

WW>2) Класс-обертка, который хранит строку как последовательность char символов, но в

WW>кодировке utf-8. Реализовать конвертеры в другие кодировки.
WW>Здесь хотелось бы узнать плюсы или минусы данного варианта.

Мы сделали все на std::string + UTF8.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.