Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Гурман от Октябрь 12, 2015, 21:27



Название: И снова про кодировки...
Отправлено: Гурман от Октябрь 12, 2015, 21:27
Кто-нибудь знает хотя бы способ получить имя текущей кодировки локали? Может я просто его прозевал... Чтобы не "System" отдало, а "Windows-1251" и т.д. - что на самом деле используется.



Название: Re: И снова про кодировки...
Отправлено: ammaximus от Октябрь 13, 2015, 10:18
qDebug ()<< QTextCodec::codecForName (nl_langinfo (CODESET))-> name()


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 13, 2015, 14:38
nl_langinfo (CODESET)
нет в MinGW :-(


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 00:11
В общем, пришлось колбасить аналогично QtCreator выбор кодировки для загружаемых файлов. Как-то Тролли с этим делом недоделали, и наверняка сами не рады.

Но есть другая проблема, тоже кодировочная, поэтому ветку отдельно не создаю. Надеюсь, заглянут и увидят те, кто уже такое решал.

Общая обстановка такая, что моё ПО может работать с одними и теми же файлами как в Windows, так и в Linux (а в будущем и в других ОС). Есть пользовательские файлы с 8-и битными текстами, кодировки которым я настраиваю явным указанием. С разными кодировками текстов я справляюсь при помощи QTextStream::setCodec( QTextCodec::codecForName(<выбранное юзером имя кодека>) ). Если в Linux при указать кодировку "Windows-1251", то русские тексты сохраняются честно в UTF-8, и всё замечательно. Но есть еще файлы настроек, базирующиеся на QSettings, для переносимости используется формат INI. Настройки тоже могут использоваться в разных ОС с разными кодировками 8-и битных символов. И конечно, настройки могут содержать русские строки. Вот тут проблема - если я указываю setIniCodec("Windows-1251"), то Qt тупо сохраняет русское содержимое настроек в виндозной кодировке, в виде 8-и битных символов, а вовсе не в UTF-8. Разумеется, потом в текстовом редакторе в Linux эти строки поправить нельзя, если что. Но самое обидное - это то, что при загрузке QSettings таких настроек в Linux приложении, они... загружаются в Windows кодировке. То есть, на выход QSettings настройки кодирует, но на вход не декодирует. Буквально - я в Linux набираю в настройках приложения строку по-русски, закрываю приложение, открываю - строка в кодировке 1251 (в файле разумеется тоже в 1251 записана).

Пока не ясно, как это побороть. Кто эту проблему решал, каким образом? Может я зевнул чего-то? Может есть способ заставить QSettings восстанавливать кодировку в "System" при загрузке INI-файлов?


Название: Re: И снова про кодировки...
Отправлено: ammaximus от Октябрь 14, 2015, 08:49
К прошлому вопросу:
#ifdef windows
qDebug()《 GetACP ();

Так и не понял зачем нужна "текстовка" кодека, тем более как это поможет кодировать файлы. Если это ваш соб твенный формат,  добавьте кодировку внутрь, как xml. Даже у ворда есть выбор кодировки, если он сам не распознал. Если простые текстовые файлы, почему бы не использовать System кодек? Им тоже можно и писать и читать.
Еще хотелось бы отметить, что запуск ПО под определенной ОС не означает, что все загружаемые файлы будут в кодировке этой ОС. Так что определенные защиты нужны.


Название: Re: И снова про кодировки...
Отправлено: ammaximus от Октябрь 14, 2015, 09:09
2. Чем вызван выбор ини? Нужно переносить настройки между машинами или загружать по сети? Я пользуюсь простым КуСеттингс в кроссплатформенных приложениях и мне безразлично как что он там сохраняет, лишь бы записывала та же программа, что и читает.


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 13:39
Я пользуюсь простым КуСеттингс в кроссплатформенных приложениях и мне безразлично как что он там сохраняет, лишь бы записывала та же программа, что и читает.

А мне нет. У меня текстовые файлы и настройки могут быть сохранены приложением в Windows, а использованы в Linux или в будущем в другой ОС. Поэтому формат INI - он поддерживается QSettings во всех ОС.

И просьба не уводить в сторону - у меня давно отлажена работа настроек, используется почти в двух десятках плагинов, ничего изменять я не буду. Вопрос только в 8-и битных кодировках, их поддержке в QSettings. Если нечего сказать по существу - лучше ничего не говорить.


Название: Re: И снова про кодировки...
Отправлено: Igors от Октябрь 14, 2015, 13:50
А если записать кодировку как строку в самой QSettings?


Название: Re: И снова про кодировки...
Отправлено: Bepec от Октябрь 14, 2015, 14:52
Установить кодировку UTF8/16 везде и не париться не вариант?


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 15:33
А если записать кодировку как строку в самой QSettings?

Я записываю, но этого мало. Это просто передача информации о том, какой кодировке был создан файл настроек. Если указать эту кодировку в setIniCodec() при загрузке, то именно в такой кодировке настройки и загружаются. А надо, чтобы они загрузились с кодировкой "System".


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 16:51
Установить кодировку UTF8/16 везде и не париться не вариант?

Тут мне кое-что не понятно. По-умолчанию Qt на самом деле и так вроде бы в UTF сохраняет, нет? Тут такой момент - у меня многие строковые настройки в приложении используются в виде const char*. Это необходимо для взаимодействия со старыми библиотеками на чистом Си. Получать const char* приходится через QByteArray QString::toLocal8Bit() и далее const char* QByteArray::constData(). Но toLocal8Bit() использует установленный кодек локали для 8-и битных символов. Если файл настроек был сохранен в Windows, и кодек явно не прописать с помощью QTextCodec::setCodecForLocale( QTextCodec::codecForName("Windows-1251") ), то в Linux вызов toLocal8Bit возвращает "кракозябры" (постоянно это нельзя делать - перестают работать русские имена файлов и каталогов). Не понятно - почему декодирование работает именно с кодеком Windows-1251, если русские буквы были сохранены в UTF. Или по-умолчанию QSettings не в UTF сохраняет? Что это тогда?

При установке кодировки UTF для INI с помощью QSettings::setIniCodec() русские буквы не загружаются в QString, в строке после загрузки настроек оказываются кодированные символы. О чем и вопрос был.


Название: Re: И снова про кодировки...
Отправлено: Bepec от Октябрь 14, 2015, 17:19
QString хранит данные в utf16, но при получении из QSettings они будут в той кодировке, что записаны.

PS сейчас эксперимент проведу.
Провел эксперимент, спокойно сохраняет - восстанавливает, данные хранятся в utf8, как и указано в кодеке.

PS по умолчанию она локаль использует стандартную, а не utf8.


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 18:28
У меня с UTF-8 получились другие чудеса - все данные, которые хранятся в виде QVariant, напрочь слетели. Например в QVariant хранятся цвета QColor - там теперь ерунда какая-то, и при загрузке старых настроек все цвета искажены.


Название: Re: И снова про кодировки...
Отправлено: Bepec от Октябрь 14, 2015, 19:11
Ну как бы логично, сохраняли вы в другой кодировке, а читать пытаетесь в utf8. Ясен пень что там бред будет.
Вам нужно старые настройки конвертировать в новый формат.
Или же просто запилить конвертирование автоматическое при чтении.

PS что бы там не писалось, QSettings это просто строки в нужной кодировке. Сменили кодировку - строки нечитабельны.


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 19:31
С UTF-8 тоже хрень получается. Сохранил в Windows настройки в UTF-8, проверил HEX-редактором - всё правильно, UTF-8. Загрузил в приложение, все строки читаются. Скопировал файл в Linux, там проверил - русские буквы в UTF-8, в HEX-редакторе тоже самое содержимое. Просматриваю файл вьюером DoubleCommander, он умеет автоматом UTF-8 определять - всё читается по-русски. Запускаю приложение в Linux, эти настройки в него загружаются - в строках бред. Причём не только после toLocal8Bit() но и просто в QString. Исходники одни и те же... Кодек устанавливаю первой строкой в конструкторе класса настроек, который наследует QSettings, но это уже после инициализации родительского класса QSettings.

Код:
VariantSettings::VariantSettings( QString filename, QObject* parent ) :
    QSettings( filename + PLUGSETEXT, QSettings::IniFormat, parent )
{
    setIniCodec( "UTF-8" );
.....

В Windows всё работает, как следует. В Linux если ввести в поле русский текст и сохранить настройки, то текст записывается в UTF-8. Но после запуска приложения из этой настройки читается бред.

Попробую собрать в Linux ваш пример. В Windows он у меня нормально отработал. PS: проверил - работает правильно...

Ну как бы логично, сохраняли вы в другой кодировке, а читать пытаетесь в utf8. Ясен пень что там бред будет.

Логично было бы для строк с кириллицей... Но испортились те настройки, которые кириллицу не содержали. Откуда она, например, в QColor?


Название: Re: И снова про кодировки...
Отправлено: Bepec от Октябрь 14, 2015, 20:21
QColor будет примерно как

QRGB(00,ff,ff)

Меняем кодировку и получаем
џ|nу(00,ff,ff)

Парсер QVariant охреневает :D


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 14, 2015, 23:21
Да черт с ними, с цветами...

В приложении Linux глухо не работает UTF-8 при загрузке настроек. В QString загружаются байты, без декодирования. В приложении Windows глухо работает как надо. Исходники идентичны. Разница в ОС, и в разрядности ОС - Windows 32 бит, Linux 64 бит. Сборка Qt и сборка самого приложения в Linux тоже 64 бит.

Но тестовый пример работает. Уже два бубна протёр в поисках что может влиять... Даже выносил setIniCodec() из конструктора на после создания объекта - не помогает.  :( Может в Qt 64 есть какая-то дыра?
...
Вроде кое-как добился загрузки в QString из UTF-8 в Linux. Но toLocal8Bit всё равно почему-то не работает без явной установки кодировки с помощью setCodecForLocale().


Название: Re: И снова про кодировки...
Отправлено: Racheengel от Октябрь 15, 2015, 01:23
Наличие/отсутствие byte order mark (BOM) рассматривалось?


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 15, 2015, 02:32
Нет. А толку? Это же всё инкапсулировано в QSettings. Хотя я могу точно сказать, что bom там не записывается.


Название: Re: И снова про кодировки...
Отправлено: Bepec от Октябрь 15, 2015, 04:11
приводите версию и ветку линуха, мб и поможем.

PS зачем вам toLocal8Bit? при использовании utf8 он нафиг не нужен )


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 15, 2015, 13:19
приводите версию и ветку линуха, мб и поможем.

PS зачем вам toLocal8Bit? при использовании utf8 он нафиг не нужен )

Linux Kubuntu 14.04. Я сам думаю, что с системой что-то не так. В Linux строки из QString, которые были загружены QSettings в UTF-8, читаются только после... установки кодировки локали Windows.

На самом деле, это не смертельно - локаль пользователю всё равно придётся выбирать, потому что она нужна для загрузки в QPlainText 8-и битных текстов данных, там в UTF-8 перейти пока нельзя. Значит я могу перед преобразованием менять локаль, затем возвращать System. Но такой поведение выглядит странно... Кроме как при загрузке в QPlainText и setCodecForTr(), "Windows-1251" нигде в приложении не используется.

Зачем toLocal8Bit я раньше писал - нужны const char* варианты строк для работы со старыми С-библиотеками. Вот тут в Linux и лезут косяки с кодировками. В Windows нет проблем.


Название: Re: И снова про кодировки...
Отправлено: Гурман от Октябрь 19, 2015, 18:26
Локальная проблема была найдена - при сборке плагинов не выполнялись действия в QMAKE_POST_LINK из-за того, что там остались двойные кавычки в групповом имени файлов для удаления. То есть, в Linux сборке было

Код:
QMAKE_POST_LINK = $$QMAKE_DEL_FILE \"$$DESTDIR/$${TMPFILE}*\"
вместо
Код:
QMAKE_POST_LINK = $$QMAKE_DEL_FILE $$DESTDIR/$${TMPFILE}*

Соответственно старые файлы не удалялись, новые поэтому не создавались, и всё ехало... И причем ведь, qmake честно генерит команду

rm -f ....

В результате всё проскакивает молча, шито-крыто, а потом очень странно не работает.
Но глобально проблема не решена - пришлось делать вызовы для принудительной установки кодировки, в которой были сохранены настройки, и для возврата System после toLocal8Bit. Поэтому тэг РЕШЕНО в заголовок не добавляю.