Russian Qt Forum
Май 27, 2024, 07:42 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: 4.4.0: Utf-8 и QTextStream::seek()  (Прочитано 5730 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« : Декабрь 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 и последующий поиск маркеров побайтно, но поскольку кроме этого необходимо произвести еще кое-какие операции со строками, код выростет раза в два (и производительность грохнется в столько же).
« Последнее редактирование: Декабрь 01, 2008, 11:03 от Racheengel » Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Alex03
Гость
« Ответ #1 : Декабрь 01, 2008, 16:10 »

Как Вы представляете seek() в символах?
Только через чтение файла с самого начала.... А это накладно и теряется всякий смысл в индексации.
Я никакого бага тут не вижу, тем более что весь файл не обязан быть текстровым.
Ну а как предложение - при индексации сохранять смещения в файле в байтах а не в символах.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #2 : Декабрь 01, 2008, 16:40 »

Ну, собственно, QTextStream-то ориентирован как раз на текстовые файлы, иначе я бы юзал QDataStream.
В принципе, теоретически можно реализовать враппер для посимвольного поиска, но... это геморойно, да...
Наверное все-таки буду читать поток побайтово.
Но все же это не очень удобно - работать с текстовым файлом как с бинарным только потому, что Utf-8 довольно дурацкая кодировка в плане того, что некоторые символы представлены 1, а некоторые 2 байтами - будь моя воля, юзал бы Utf-16, но... такие исходные файлы, ничего не поделать...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Tonal
Гость
« Ответ #3 : Декабрь 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 организуя окно. Если реализовать нормально (кольцевой буфер, например), на скорость это мало повлияет. Улыбающийся
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #4 : Декабрь 03, 2008, 12:04 »

В принципе, я реализовал все с QByteArray.
Мне маркеры надо искать по всему файлу, так что я читаю все сразу в память и ищу через indexOf().
Получаю бинарный индекс, который потом отлично работает с seek().
Ну а когда надо прочитать собственно текст по маркеру, делаю seek(), потом выставляю кодек в Utf-8 и читаю уже как строку. Все работает как надо.
Спасибо всем за советы Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.061 секунд. Запросов: 19.