Russian Qt Forum

Qt => Базы данных => Тема начата: marbius от Май 11, 2011, 14:44



Название: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 11, 2011, 14:44
Доброго времени суток.

Имею базу данных sqlite3 в кодировке windows-1251. При попытке отображения данных в QTableView через QSqlTableModel на выходе получаю вопросы ����� для кириллических символов.

После редактирования данных непосредственно в QTableView кириллические символы отображаются корректно и в базу попадают в кодировке utf-8.

Установка кодеков мне не помогла:
Код
C++ (Qt)
QTextCodec *codec=QTextCodec::codecForName("windows-1251");
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForTr(codec);
 

Подскажите, как можно сохранить возможность отображения и сохранения кириллических символов в windows-1251.
Перекодировка всех данных базы в utf-8 вроде бы и решает проблему, но данные используются также и в другом ПО, поэтому хотелось бы обойтись без лишних перекодировок БД.

Спасибо.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: blood_shadow от Май 11, 2011, 15:21
Доброго времени суток.

Имею базу данных sqlite3 в кодировке windows-1251. При попытке отображения данных в QTableView через QSqlTableModel на выходе получаю вопросы ����� для кириллических символов.

После редактирования данных непосредственно в QTableView кириллические символы отображаются корректно и в базу попадают в кодировке utf-8.

Установка кодеков мне не помогла:
Код
C++ (Qt)
QTextCodec *codec=QTextCodec::codecForName("windows-1251");
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForTr(codec);
 

Подскажите, как можно сохранить возможность отображения и сохранения кириллических символов в windows-1251.
Перекодировка всех данных базы в utf-8 вроде бы и решает проблему, но данные используются также и в другом ПО, поэтому хотелось бы обойтись без лишних перекодировок БД.

Спасибо.
не внимательно документацию читаем..
QTextCodec *codec=QTextCodec::codecForName("Windows-1251");


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 11, 2011, 15:31
не внимательно документацию читаем..
QTextCodec *codec=QTextCodec::codecForName("Windows-1251");

Мои извинения, но это какой-то слишком тонкий юмор для меня  :(

В моей документации следующее:
Цитировать
QTextCodec * QTextCodec::codecForName ( const char * name ) [static]
Searches all installed QTextCodec objects and returns the one which best matches name; the match is case-insensitive. Returns 0 if no codec matching the name name could be found.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: blood_shadow от Май 11, 2011, 15:37
Мои извинения, но это какой-то слишком тонкий юмор для меня  :(

В моей документации следующее:
Цитировать
QTextCodec * QTextCodec::codecForName ( const char * name ) [static]
Searches all installed QTextCodec objects and returns the one which best matches name; the match is case-insensitive. Returns 0 if no codec matching the name name could be found.
правильно, ты имя кодека не правильно написал, ты написал:
QTextCodec::codecForName("windows-1251"); а надо:
QTextCodec::codecForName("Windows-1251");
посмотри в Detailed Description класса QTextCodec


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 11, 2011, 15:52
правильно, ты имя кодека не правильно написал, ты написал:
QTextCodec::codecForName("windows-1251"); а надо:
QTextCodec::codecForName("Windows-1251");
посмотри в Detailed Description класса QTextCodec

Убейте меня, если "the match is case-insensitive", не означает, что поиск РЕГИСТРОНЕЗАВИСИМЫЙ  ???

В любом случае, blood_shadow, я даже проверил Ваше утверждение - не помогло.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: blood_shadow от Май 11, 2011, 16:04
правильно, ты имя кодека не правильно написал, ты написал:
QTextCodec::codecForName("windows-1251"); а надо:
QTextCodec::codecForName("Windows-1251");
посмотри в Detailed Description класса QTextCodec

Убейте меня, если "the match is case-insensitive", не означает, что поиск РЕГИСТРОНЕЗАВИСИМЫЙ  ???

В любом случае, blood_shadow, я даже проверил Ваше утверждение - не помогло.
а где делаете установку кодеков? я думаю что сама проблема в конвертации строк именно между
QSqlTableModel и базой данных,
QTextCodec *codec=QTextCodec::codecForName("windows-1251");
QTextCodec::setCodecForCStrings(codec);
надо сделать либо в конструкторе подкласса QSqlTableModel(если он есть)либо до создания модели,
например в меин ф-ции, а вообще QString - это utf-16


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: LisandreL от Май 11, 2011, 16:06
Имею базу данных sqlite3 в кодировке windows-1251.
Ложь и провокация. ;D
SQLite поддерживает только utf кодировки:
http://www.sqlite.org/pragma.html#pragma_encoding
Собственно в этой кодировке QSqlTableModel вам текст и отображает.
Никакой «базы данных sqlite3 в кодировке windows-1251» существовать не может в принципе, но может быть «база данных sqlite3 в кодировке utf-8, в которую криворукий программист нечитающий документацию записал текст в кодировке windows-1251».

Собственно в чём проблема писать в БД в utf-8? Или эту же самую базу использует другое ПО, считающее, что там данные в CP1251? Тогда придётся отказываться от QSqlTableModel и читать/писать самому через QSqlQuery.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 11, 2011, 16:13
Код тестового приложения:
Код
C++ (Qt)
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
 
   QTextCodec *codec=QTextCodec::codecForName("Windows-1251");
   QTextCodec::setCodecForCStrings(codec);
 
   QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
   db.setDatabaseName(qApp->applicationDirPath()+QDir::separator()+"database.s3db");
   QSqlTableModel model;
   model.setTable("instr");
   model.select();
 
   QTableView view;
   view.setModel(&model);
   view.show();
   return a.exec();
 
}
 


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 11, 2011, 16:18
Собственно в этой кодировке QSqlTableModel вам текст и отображает.
Никакой «базы данных sqlite3 в кодировке windows-1251» существовать не может в принципе, но может быть «база данных sqlite3 в кодировке utf-8, в которую криворукий программист нечитающий документацию записал текст в кодировке windows-1251».

В принципе, да, это больше похоже на правду ))


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: LisandreL от Май 11, 2011, 17:28
Так всё же в чём проблема писать в БД в utf-8? Или эту же самую базу использует другое ПО, считающее, что там данные в CP1251?


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 12, 2011, 03:18
Так всё же в чём проблема писать в БД в utf-8? Или эту же самую базу использует другое ПО, считающее, что там данные в CP1251?
Да, именно так. База уже наполнена данными и "другое ПО" оперирует ими только в win1251. "Другое ПО" уже не переделать, если не переписать с нуля: исходников как всегда нет; да, и написано оно, похоже, на Delphi, ну или Builder'е.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: LisandreL от Май 12, 2011, 06:17
Если дадите небольшой пример своей базы, то могу опробовать одну идею... Много записей не надо, но обязательно с такой кириллицей.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: AlphaGh0St от Май 12, 2011, 10:20
...хм...может малость не в тему, но всё-же попробуй вот этот код

QTextCodec::setCodecForTr(QTextCodec::codecForName("Windows-1251"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("Windows-1251"));


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: LisandreL от Май 12, 2011, 17:29
AlphaGh0St, вы правы - это абсолютно не в тему.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: marbius от Май 13, 2011, 13:52
Если дадите небольшой пример своей базы, то могу опробовать одну идею... Много записей не надо, но обязательно с такой кириллицей.

Да, пожалуйста. Первые 10 записей одной из таблиц.


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: LisandreL от Май 13, 2011, 22:25
Да, пожалуйста. Первые 10 записей одной из таблиц.
Вот решение костыльное немного более, чем полностью:
Код
C++ (Qt)
#include <QApplication>
#include <QTextCodec>
#include <QSqlTableModel>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QTableView>
 
class CrutchesModel: public QSqlTableModel
{
   QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
   {
       QVariant value = QSqlTableModel::data(index, role);
       if (value.type()==QVariant::String)
       {
           // если строка, то читаем шестнадцатиричное представление поля и из него получаем нашу CP1251 строку
           QString queryString = "SELECT HEX([" + database().record(tableName()).fieldName(index.column()) + "]) FROM "+ tableName();
           if (!filter().isEmpty())
               queryString.append(" WHERE ").append(filter());
           if (!orderByClause().isEmpty())
               queryString.append(' ').append(orderByClause());
           queryString.append(" LIMIT 1 OFFSET ").append(QString::number(index.row())).append(";");
           QSqlQuery query = database().exec(queryString);
           if (query.next())
           {
               return QString(QByteArray::fromHex(query.value(0).toByteArray()));
           }
           else
           {
               return QString();
           }
       }
       return value;
   };
 
   bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)
   {
       if (value.type()==QVariant::String)
       {
           // строку пишем как массив байт
           return QSqlTableModel::setData(index, value.toString().toAscii(), role);
       }
       return QSqlTableModel::setData(index, value, role);
   };
};
 
int main(int argc, char *argv[])
{
   QTextCodec *codec=QTextCodec::codecForName("Windows-1251");
   QTextCodec::setCodecForCStrings(codec);
   QApplication a(argc, argv);
 
   QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE");
   db.setDatabaseName("database.s3db");
   CrutchesModel model;
   model.setTable("instr");
   model.select();
 
   QTableView view;
   view.setModel(&model);
   view.show();
   return a.exec();
}
Собственно в CrutchesModel переопределяем data и setData.
Увы родное data() возвращает сразу одни "знаки вопроса в ромбиках" и исходную строку приходится узнавать отдельным запросом к БД.
Так же вынужден заметить, что писать в setData оно реально будет не строку, а ByteArray (т.е. в понятиях SQLite'а - blob). Скорее всего это не вызовет проблем - SQLite к типам полей относится весьма фривольно, однако лучше эту подправленную БД опробовать на Delphi-программе, с которой вы работаете, чтобы убедиться что ничего не поломалось.

Исходный код программы в прикреплённом файле:


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: amabilisa от Март 29, 2017, 15:12
Спасибо! Выручили!

У меня та же проблема. "Умники" из другого отдела засунули в базу через API SQLite данные в 1251.

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

Модель у меня от QAbstractItemModel. Qt 5.4.

Ломаю голову, как заставить базу понять запрос из моего кода:

select ANTENS.ID from ANTENS where ANTENS.ANTEN_NAME = 'Антенна_1'

Пробовала сравнивать хексы, но не помогло.
Может быть, есть какие-то мысли, как это осуществить?

Вот, что было испробовано:

fieldText = QString("Антенна_1").toLocal8Bit().toHex();
queryText = QString("select ANTENS.ID from ANTENS where HEX(ANTENS.ANTEN_NAME) = HEX('" + fieldText  +"')").toLocal8Bit();

Но
query.exec(queryText);
упорно возвращает ноль результатов.

Даже напрямую в SQLite Browser запрос ничего не вернул.
select ANTENS.ID from ANTENS where HEX(ANTENS.ANTEN_NAME) = HEX('C0EDF2E5EDEDE05F31')

где C0EDF2E5EDEDE05F31 -- результат выбора в хексе названия антенны по её id (та самая "Антенна_1").

Что делаю не так, ребят?


Название: Re: Проблемы кодировки cp1251 (sqlite + QSqlTableModel + QTableView)
Отправлено: lit-uriy от Март 29, 2017, 18:36
amabilisa, а сама БД в какой кодировке?