Russian Qt Forum

Qt => Общие вопросы => Тема начата: Racheengel от Декабрь 01, 2008, 10:58



Название: 4.4.0: Utf-8 и QTextStream::seek()
Отправлено: Racheengel от Декабрь 01, 2008, 10:58
Всем привет :)
Запостил сюда, ибо не знаю, куда лучше по теме.

В общем есть такая задача:
текстовый файл в кодировке Utf-8 (очень большой), который необходимо индексировать (пробежаться по нему однажды, найти некоторые маркеры и выгрузить в индексный файл их позиции).

Использую такой вариант:

Код:
QFile f(...);
...
QTextStream ts(&f);
ts.setCodec("Utf-8");
QString s = ts.readAll();
...
// тут проход по s, поиск маркеров и сохранение индексов в файл
...

Проблема в том, что последующее чтение с помощью QTextStream::seek(index) позиционирует указатель на неверный индекс, а именно - QTextStream::seek() игнорирует установленный кодек и устанавливает смещение в байтах, а не в символах (как это должно быть по хорошему). В принципе, я считаю это багом и намерен зарепортить тролям, ибо read(size) работает как надо в отличие от seek() (т.е. читает size символов, а не байтов).

Знает ли кто адекватное решение? Мне в голову приходит только чтение в виде QByteArray и последующий поиск маркеров побайтно, но поскольку кроме этого необходимо произвести еще кое-какие операции со строками, код выростет раза в два (и производительность грохнется в столько же).


Название: Re: 4.4.0: Utf-8 и QTextStream::seek()
Отправлено: Alex03 от Декабрь 01, 2008, 16:10
Как Вы представляете seek() в символах?
Только через чтение файла с самого начала.... А это накладно и теряется всякий смысл в индексации.
Я никакого бага тут не вижу, тем более что весь файл не обязан быть текстровым.
Ну а как предложение - при индексации сохранять смещения в файле в байтах а не в символах.


Название: Re: 4.4.0: Utf-8 и QTextStream::seek()
Отправлено: Racheengel от Декабрь 01, 2008, 16:40
Ну, собственно, QTextStream-то ориентирован как раз на текстовые файлы, иначе я бы юзал QDataStream.
В принципе, теоретически можно реализовать враппер для посимвольного поиска, но... это геморойно, да...
Наверное все-таки буду читать поток побайтово.
Но все же это не очень удобно - работать с текстовым файлом как с бинарным только потому, что Utf-8 довольно дурацкая кодировка в плане того, что некоторые символы представлены 1, а некоторые 2 байтами - будь моя воля, юзал бы Utf-16, но... такие исходные файлы, ничего не поделать...


Название: Re: 4.4.0: Utf-8 и QTextStream::seek()
Отправлено: Tonal от Декабрь 03, 2008, 09:41
Ежели маркеры всегда в пределах одной строки, то алгоритм такой:
Код
Python
def create_mark_index(data_name, find_mark, save_mark):
 QTextStream stream(data_name);
 while not stream.atEnd():
   pos = stream.pos()
   line = stream.readLine()
   mark = find_mark(line)
   if mark:
     save_mark(pos, line, mark)
 
Здесь find_mark принимает очередную строку и возвращает нужные данные о маркере или False если ничего не нашла.
save_mark - принимает позицию старта строки, саму строку и данные о маркере, которые вернула find_mark.
Скорость будет весьма неплохой. Памяти потребуется немного.
Пример ишет первое вхождение любой подстроки из eni, beni, riki, taki в строке файла данных и выводит на стандартный вывод позицию строки, позицию найденной подстроки и её саму:
Код
Python
def find_mark(line):
 return re.search('eni|beni|riki|taki', line, re.I)
 
def save_mark(pos, line, mark):
 print pos, mark.start(), mark.group()
 
create_mark_index(data_name, find_mark, save_mark)
 
Переложить на С++ труда не составляет.

Если маркеры могут захватывать несколько строк - придётся несколько усложнить create_mark_index организуя окно. Если реализовать нормально (кольцевой буфер, например), на скорость это мало повлияет. :)


Название: Re: 4.4.0: Utf-8 и QTextStream::seek()
Отправлено: Racheengel от Декабрь 03, 2008, 12:04
В принципе, я реализовал все с QByteArray.
Мне маркеры надо искать по всему файлу, так что я читаю все сразу в память и ищу через indexOf().
Получаю бинарный индекс, который потом отлично работает с seek().
Ну а когда надо прочитать собственно текст по маркеру, делаю seek(), потом выставляю кодек в Utf-8 и читаю уже как строку. Все работает как надо.
Спасибо всем за советы :)