Быстрый поиск меток в текстовом файле и работа с ними

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Roland
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 28.04.2005 (Чт) 10:30

Быстрый поиск меток в текстовом файле и работа с ними

Сообщение Roland » 12.06.2005 (Вс) 20:30

Здравствуйте.
Сразу прощу прощения за глупые вопросы, но я не программист, просто иногда приходится писать небольшие программки на VBA, Exel.

Задача: Есть текстовый файл, размером 500 кб. В нем содержится произвольный текст, в котором разбросаны текстовые "метки", длиной около 20 символов, количеством 1500 штук. Есть массив этих меток (берется из таблицы экселя).

Необходимо переписать в новый файл все куски исходного файла, которые содержат метки из массива, в таком порядке, в каком метки идут в массиве, этот порядок часто меняется.
Кусок - это последовательность строк файла не содержащая пустых строк - "абзац".
Задача упрощается тем, что все метки уникальны, встречаются в файле в одном экземпляре и тем, что метка может встретится только в первой строке "Абзаца".

C горем пополам и помощью знакомых удалось наваять программу:
For k = 1 To UBound(Z) ' Z - массив с текстовыми метками
Do While Not EOF(1)
Line Input #1, curStr ' #1 - исходный файл
If InStr(curStr, Z(k)) > 0 Then
Print #2, curStr ' запись метки в файл #2
Line Input #1, curStr
Do While Trim(curStr) <> "" ' копировать пока не встретится пустая строка
Print #2, curStr
If EOF(1) Then Exit Do
Line Input #1, curStr
Loop
Print #2, vbCrLf ' добавить в конец пустую строку
Exit Do ' каждая метка уникальна,поэтому искать ее еще раз не надо
End If
Loop
Seek 1, 1 ' переходим в начало файла
Next k

В кратце, чтобы не читать программу, алгоритм такой:
1. Метку из массива ищем в исходном файле, файл читаем с помощью Line input, если нашли, то вставляем строку с меткой в новый файл и все строки, следующие за ней, до пустой строки.
2. возвращяемся в начало файла и ищем вторую метку, и т. д., до конца массива с метками.

Проблема в том, что все это дело обрабатывается около 30 секунд. Т. к. размеры файла и кол-во меток быстро увеличивается, нужно ускорить программу.
Есть идея: перед обработкой файла занести в новый массив для каждой метки ее позицию в файле и не искать метки, а сразу переходить к позиции метки и производить необходимые операции.
Но у меня не получается это реализовать.
Похоже, что при считывании Line Input текущая позиция автоматически не увеличивается на длину строки.
Попытки увеличивать некоторую переменную на длину строки, получаемую с помощью Len к успеху не привели.

Буду очень благодарен, если вы сможете мне помочь в реализации этой идеи или подскажите
другой вариант программы, ускоряющий процесс.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 13.06.2005 (Пн) 10:26

можно ли увидеть пример этого текстового файла ?

и файла в который он должен преобразоваться?

а то непонятен смысл задачи
Весь мир матрица, а мы в нем потоки байтов!

Roland
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 28.04.2005 (Чт) 10:30

Сообщение Roland » 13.06.2005 (Пн) 12:15

Viper! - конечно! привожу куски из файлов:
===============Массив меток:======================
................
\zadachaz{050106z}
\zadachaz{060106z}
\zadachaz{030106z}
\zadachaz{040106z}
................


============Это кусок исходного файла:================
.....................

\zadachaz{030106z} Найдите площадь фигуры,
ограниченной линиями $y=\f{1}{x^2}$, $y=0$, $x=1$, $x=5$.

\otvetz{030106z}$0,\!8$.

\zadachaz{040106z} На рисунке \ref{p040106} изображена прямая,
являющаяся касательной к графику функции $y=f(x)$ в точке $(x_0;f(x_0))$.
Найдите значение производной $y=f'(x)$ в точке $x_0$.
\begin{figure}[!t!b!p]
\centering \includegraphics{040106.eps} \caption{} \label{p040106}
\end{figure}

\otvetz{040106z}$1,\!5$.

\zadachaz{050106z} При каком значении $a$ функция
$y=\arctg(-5x^2+3(a+1)x-17)$ имеет максимум в точке с абсциссой $-0,\!6$?

\otvetz{050106z}$-3$.

\zadachaz{060106z} Найдите наибольшее целое число, входящее в область
значений функции $y=27\log_{27}(\sqrt3\cos^2 x+\sin^2x)$.

\otvetz{060106z}$4$.
..........................


============Исходя из порядка меток в конечном файле должно получится:============
.....................
\zadachaz{050106z} При каком значении $a$ функция
$y=\arctg(-5x^2+3(a+1)x-17)$ имеет максимум в точке с абсциссой $-0,\!6$?

\zadachaz{060106z} Найдите наибольшее целое число, входящее в область
значений функции $y=27\log_{27}(\sqrt3\cos^2 x+\sin^2x)$.

\zadachaz{030106z} Найдите площадь фигуры,
ограниченной линиями $y=\f{1}{x^2}$, $y=0$, $x=1$, $x=5$.

\zadachaz{040106z} На рисунке \ref{p040106} изображена прямая,
являющаяся касательной к графику функции $y=f(x)$ в точке $(x_0;f(x_0))$.
Найдите значение производной $y=f'(x)$ в точке $x_0$.
\begin{figure}[!t!b!p]
\centering \includegraphics{040106.eps} \caption{} \label{p040106}
\end{figure}
.....................

То есть файл в текстовом формате - сборник задач в TeX-е (такой текстовый редактор,
специально для математики и типографий). Нужно сделать выборку некоторых (часто всех) задач
из этого файла в указанном порядке (тут же сделать выборку ответов и решений, но это задача аналогичная исходной)
и записать в новый файл задачи отделяются пустыми строками.
Здесь все метки идут с начала строки, бывает, что метки идут не с начала строки,
но всегда в первой строке обязательно. Вся работа идет в VBA Exel.

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Сообщение Viper » 14.06.2005 (Вт) 18:17

алгоритм решения словами:

1. считать все задачи, то есть от начала метки до пустой строки в строковой массив или (луший вариант) в коллекцию, в которой ключом будет метка
2. создается второй массив (коллекция) куда все это копируется в нужной последовательности. для коллекций нужно просто последовательно получить элементы коллекции по метке. если при помощи массивов, то надо искать строку-метку в строке-элементе массива
3. записаить все это в новый файл, не забывая всталять пустые строки

вроде ничего не забыл
Весь мир матрица, а мы в нем потоки байтов!

Roland
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 28.04.2005 (Чт) 10:30

Сообщение Roland » 08.08.2005 (Пн) 20:34

!Viper! Спасибо большое за помощь!
Вариант с коллекцией поименованной просто СУПЕР ускорил процесс раз в 20 минимум.
А вариант с массивом практически никак не ускорял, только чуть-чуть.
Отвечаю так поздно, потому что обстоятельства так сложились...

lord0n
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 845
Зарегистрирован: 30.06.2005 (Чт) 9:55
Откуда: Moskow

Сообщение lord0n » 09.08.2005 (Вт) 5:50

я бы сделал по другому:
открыл файл в екселе и стандартным поиском все нашел.
я таким оброзом ускорил работу с 30 мин до 3

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 09.08.2005 (Вт) 7:19

Я бы сделал так.
1. 500Кб можно сразу загрузить в память.
2. Метки искать с помощью InStr.
3. Все.

Может и не быстрее коллекций, но куда менее ресурсоемко.

Код примерно такой:
Код: Выделить всё
' Marks() - массив с метками
Dim FN As Integer, buff As String, I As Long, P0 As Long, P As Long
FN = FreeFile()
Open "C:\source.txt" For Binary Access Read As #FN
buff = String$(LOF(FN), 0)
Get #FN, , buff
Close #FN
FN = FreeFile()
Open "C:\destination.txt" For Output As #FN
For I = LBound(Marks) To UBound(Marks)
  P0 = InStr(1, buff, Marks(I))
  If P0 > 0 Then
    P = InStr(P0, buff, vbNewLine & vbNewLine)
    If P = 0 Then P = Len(buff) + 1
    Print #FN, Mid$(buff, P0, P - P0)
    Print #FN,
  End If
Next I
Close #FN
Lasciate ogni speranza, voi ch'entrate.

Drag
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 85
Зарегистрирован: 29.01.2005 (Сб) 23:54
Откуда: Москва

Сообщение Drag » 10.05.2006 (Ср) 21:12

А можно ли как-нибудь упростить вот это:
Код: Выделить всё
   
    Dim p As Integer, ClearStr As String,
    Open App.path + "\FactDat.dat" For Input As #2
    For p = 1 To 8
        Input #2, ClearStr
    Next
    For p = 1 To SType
        Input #2, .ProdTime
        Input #2, .ProductType
        Input #2, .ResType(1)
        Input #2, .ResType(2)
        Input #2, .ResType(3)
        Input #2, .NOP
        Input #2, IDstr
        Input #2, ClearStr
    Next
    Close #2

Здесь, в зависимости от SType объекта ему присваиваются определенные свойства. Просто довольно заметно будет тормозить, если SType перевалит за 1000. Фактически, мне нужно, чтобы вместо двух циклов сразу находились строки для конкретного SType.
PS: В файле FactDat первые восемь строк - коментарии


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot, Google-бот и гости: 149

    TopList