текстовой конвертор

Модераторы: Romeo, Hawk, Absurd, WinMain, DeeJayC

Ответить
fallologia
Сообщения: 20
Зарегистрирован: 22 июл 2005, 11:51

текстовой конвертор

Сообщение fallologia » 22 июл 2005, 11:54

Здравствуйте!
Вопрос мой по C++ такой:
в программе-текстовом конверторе для замены строк я использую функции:
...
if(m_bVocView) m_sReadFromFile.Replace(" # "," \r\n ");
if(m_bVocView) m_sReadFromFile.Replace("\\\\ ","\r\n\r\n ");
if(m_bVocView) m_sReadFromFile.Replace("\\ ","\r\n ");
if(m_bVocView) m_sReadFromFile.Replace("\r\n~~~","");
....
Проблема в том, что этих текстовых замен много, а текстовой файл большой (10 Мб).
В результате программе приходится читать файл от начала до конца много раз. И, если файл большой, подвисает. Как сделать так, чтобы все замены проводились на одном заходе?.. То есть заменить всю эту конструкцию на одну сплошную и стройную программную дорожку, допустим:
if (m_bVocView)
{...
Как тут обозначить, что читаемая строчка может быть одной, второй, третьей, и, исходя из этих вариантов, предписать программе произовдить ту или иную замену на одном заходе.


И вторая часть этого вопроса. Чтобы производить в файле замены я последовательно использую функции:
CreateFile
ReadFile
WriteFile
В результате файл вначале загружается в виртуальную память, в которой мучается вышеизложенными заменами по многу раз, а только потом пишется на диск.
А можно ли сделать конвертацию "на лету", чтобы во время своеобрзаного копирования файла из одного своего расширения в другое производились бы и замены?.. Пытался делать все через функцию openURL, файл красиво и быстро копируется, но замены строк в нем никакими выкрутасами произвести пока не удалось. Посоветуйте Ваши решения и этой проблемы.

Аватара пользователя
WinMain
Сообщения: 912
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Сообщение WinMain » 22 июл 2005, 17:30

Если у тебя текстовый файл, то можно не грузить его в память сразу весь целиком, особенно если он большой. Читай его построчно.
Т.е. открываешь два файла: один исходный для чтения, а другой результирующий для записи. Только их нужно открывать в текстовом режиме, чтобы комбинация символов \r\n воспринималась как один символ перевода строки. Далее функцией fgets() читаешь в цикле исходный файл построчно, пока не достигнешь конца потока (проверка функцией feof()). Далее в строке делай любые манимуляции с текстом.
Одиночные символы можно менять за один проход с помощью операторов switch - case. А вот если комбинация символов, то придётся каждый раз перебирать строку для каждой комбинации.
Потом эту преобразованную строку записываешь в результирующий файл. И так цикл повторяется, пока не прочитаешь весь исходный текст до конца. А чтобы программа не подвисала, можно запустить эту процедуру в отдельном потоке. А основной поток приложения при этом должен дождаться сообщения от порождённого о завершении процедуры.

fallologia
Сообщения: 20
Зарегистрирован: 22 июл 2005, 11:51

Сообщение fallologia » 22 июл 2005, 20:25

WinMain, спасибо. Попытаюсь сделать. :idea:
Если у тебя текстовый файл, то можно не грузить его в память сразу весь целиком, особенно если он большой. Читай его построчно.
Т.е. открываешь два файла: один исходный для чтения, а другой результирующий для записи.
А при этом не получиться так, что при нарезке этих фрагментов кусок необходимой замены окажется в нынешнем фрагменте, а следущий кусок - в последующем, так что программа этой замены и не произведет?..
Кроме того, насколько более медленным такой построчный способ перебора может оказаться по сравнению с тем, если файл загружен целиком в виртуальную память?..

А может ли что выйти путного, если попытаться работать с массивами. Типа как в JavaScript:

Код: Выделить всё

Lat=new Array(
"''","w","j","yu","ye","ya","zh","'","ch","c","u","k");
Rus=new Array(
"Ь","щ","ё","ю","э","я","ж","ь","ч","ц","у","к")
function LatRus(flag) 
{
if (flag==1) 
{str=document.trform.textlat.value;
for (i=0;i<66;i++){re=RegExp(Lat[i],"g");
str=str.replace(re,Rus[i]);} 
document.trform.textrus.value=str;}}
Только все отредактировать для С++?.. А какие при применении этого способа массивов замены могут быть подвохи?..

Аватара пользователя
WinMain
Сообщения: 912
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Сообщение WinMain » 25 июл 2005, 15:52

Если ты будешь читать текст построчно, т.е. от начала строки и до её завершения (символ перевода каретки), то расчленения фрагмента не произойдёт по определению, если конечно не нарушены правила переноса текста в строке. Метод Replace() имеется в классе CString библиотеки MFC. В классе std::string есть аналогичный метод, но он выполняет лишь одиночную замену, поэтому для него нужно будет написать отдельную процедуру поиска и замены фрагментов текста в строке.
По поводу скорости построчного чтения в отличие от сплошной загрузки файла, то здесь ты существенной разницы не заметишь. К тому же тебе не нужно предварительно узнавать размер файла и выделять память соответствующего размера, а потом проверять, корректно ли была выделена память, да ещё не забыть её правильно удалить в конце процедуры. Для строки ты можешь просто локально объявить символьный массив порядка одного-двух килобайт и в него читать поочерёдно строки из файла.

fallologia
Сообщения: 20
Зарегистрирован: 22 июл 2005, 11:51

Сообщение fallologia » 27 июл 2005, 07:20

А возможно ли при построчном чтении сделать так, чтобы сразу считывалось и обрабатывалось не одна лишь строчка, а какое-нибудь целое количество строк в пределах обусловленного размера, допустим 48 000?.. То есть чтобы за раз бралось целое количество строк, которые умещаются в этом размере?..
Для строки ты можешь просто локально объявить символьный массив порядка одного-двух килобайт и в него читать поочерёдно строки из файла.
Пожалуйста, немного об этом поподробнее. Что это дает?.. И вновь-таки, при этом не нарушается ли строчка?..

Аватара пользователя
WinMain
Сообщения: 912
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Сообщение WinMain » 27 июл 2005, 14:03

Можно и весь файл загрузить, но тогда лучше не в сплошной массив, а в какой-нибудь динамический контейнер строк. Если стандартной библиотекой шаблонов пользоваться, то этот контейнет можно представить так: std::vector<std::string>.
В библиотеке MFC есть готовый контейнер строк CStringList.
В контейнер поочерёдно загоняешь строки из текста, а потом с ними работаешь, как с элементами массива. При этом тебе не нужно заботиться о физическом размере массива, а после завершения процедуры, выделенная память будет корректно освобождена.
При чтении строк из текста, искомый фрагмент может быть разделён между строками лишь в том случае, если строка слишком длинная и её длина превышает размер буфера, используемого для чтения из файла и при этом искомый фрагмент находится как раз на границе этого буфера. Но обычно текстовые строки редко бывают длиннее килобайта, поэтому один-два килобайта для буфера тебе хватит.

Ответить