Работа .findNext в больших таблицах

Автор ArVorozh, 8 октября 2015, 10:00

0 Пользователи и 1 гость просматривают эту тему.

ArVorozh

Появилась задача обработать здоровую таблицу с 500к строк. И дело вроде привычное, но оказалось, что конструкции вида

aDescriptor = oRange.createSearchDescriptor()
With ogrnDescriptor
.SearchString = "[0-9]{13,15}"
.SearchWords = True
.SearchType = 1
.SearchRegularExpression = True
End With
aFound = etcRange.findNext( oFound, aDescriptor)

дико тормозят, причем etcRange задаётся не большой- порядка 1х20 ячеек. При пошаговом выполнении макроса каждый .findNext выполняется порядка 3-4 секунд, что слишком долго- вызывается он порядка 20к раз за выполнение макроса. Есть какие-либо способы ускорить выполнение этой функции или легче использовать перебор строк совместно CreateUnoService("com.sun.star.util.TextSearch") ?

rami

Цитата: ArVorozh от  8 октября 2015, 08:00Есть какие-либо способы ускорить выполнение этой функции или легче использовать перебор строк совместно CreateUnoService("com.sun.star.util.TextSearch") ?
Выложите образец таблицы с полным макросом. findNext не должен тормозить, ведь поиск идёт до первого встречного.

ArVorozh

код приложил,  файл закинул в дропбокс, т.к. здоровый. Заметил, что один findNext выполняется быстро, а тот, который ищет слово "Адрес", выполняется крайне долго. 
Sub Main
openSheet1 = ThisComponent.Sheets (0)
Dim oDescriptor 'параметры поиска порядковых номеров
Dim addr1Descriptor 'параметры поиска адресов
oRange = openSheet1.getCellRangeByPosition(1,0,1,200) 'область поиска порядковых номеров

'задаём поисковые запросы----------------------------------------------------------------------------------------------
oDescriptor = oRange.createSearchDescriptor()
With oDescriptor
.SearchString = "[0-9]{1,4}"
.SearchWords = True
.SearchType = 1
.SearchRegularExpression = True
End With

addr1Descriptor = oRange.createSearchDescriptor()
With addr1Descriptor
.SearchString = "Адрес"
.SearchWords = True
.SearchType = 1
.SearchRegularExpression = True
End With
'--------------------------------------------------------------------------------------------------------------------------
Dim oFound 'результат поиска и условие остановки поиска
Dim nxtFound 'следующая
Dim addr1Found
Dim i as Integer
oFound = oRange.GetCellByPosition (0,0) 'инициализация

Do While Not IsNull(oFound)
oRange = openSheet1.getCellRangeByPosition(1,oFound.CellAddress.Row,1,oFound.CellAddress.Row+400)
oFound = oRange.findNext( oFound, oDescriptor)
if Not IsNull(oFound) then
'поиск следующего номер-адреса строки
nxtFound = oRange.findNext( oFound, oDescriptor)
if isNull (nxtFound) then
nxtFound = openSheet1.getCellByPosition ( oFound.CellAddress.Column, oFound.CellAddress.Row+20)
End if
etcRange = openSheet1.getCellRangeByPosition(3,oFound.CellAddress.Row,3,nxtFound.CellAddress.Row) 'область поиска адреса
'поиск Адрес
addr1Found =  etcRange.findNext( oFound, addr1Descriptor)
end If
Loop
End Sub

JohnSUN

А какая необходимость в addr1Descriptor.SearchRegularExpression = True ? Слово как слово, искать его напрямую да и дело с концом...
Если я правильно прочитал .getCellRangeByPosition(3,oFound.CellAddress.Row,3,nxtFound.CellAddress.Row), то речь идёт об одной ячейке в колонке D в только что найденной строке? Так, может быть, стоит просто считать текст из этой ячейки и дальнейший поиск вести не в таблице, а просто в текстовой строке? Ну, InStr(), или Split(), или цикл по символам...
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

ArVorozh

> А какая необходимость в addr1Descriptor.SearchRegularExpression = True ?
никакой- пережитки старых правок. с False время выполнения не меняется.
> речь идёт об одной ячейке в колонке D
не, там примерно строк 20 в один столбец. от oFound до nxtFound
циклы, безусловно, попробую, но очень уж нравится лаконичность поиска по ячейкам без цикла.

JohnSUN

Цитата: ArVorozh от  8 октября 2015, 14:53
не, там примерно строк 20 в один столбец. от oFound до nxtFound
циклы, безусловно, попробую, но очень уж нравится лаконичность поиска по ячейкам без цикла.
А, точно! Не внимательно читал...
Дополнительный вопрос: почему findNext, а не findAll? Или, скажем, не просто getDataArray?
О каком из Calc'ов, кстати, идёт речь?
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

ArVorozh

> Версия: 4.4.3.2
на нём.
>  почему findNext, а не findAll? Или, скажем, не просто getDataArray?
а хз)) не нашёл их пока. изучение api а меня далеко не академическое- много пробелов.

ArVorozh

В итоге решил проблему дооолгой работы .findNext циклом с поиском текста в ячейке. выложу "чтобы было") делал на LibreOffice 4.4.3.2
Sub Main
openSheet1 = ThisComponent.Sheets (0)

oRange = openSheet1.getCellRangeByPosition(1,0,1,500000) 'область поиска
'задаём поисковые запросы----------------------------------------------------------------------------------------------
'поиск позиции
oDescriptor = oRange.createSearchDescriptor()
With oDescriptor
.SearchString = "[0-9]{1,4}"
.SearchWords = True
.SearchType = 1
.SearchRegularExpression = True
End With
'поиск огрн
ogrnSearch =  CreateUnoService("com.sun.star.util.TextSearch")
ogrnOptions = CreateUnoStruct("com.sun.star.util.SearchOptions")
With ogrnOptions
.algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
.searchString = "[0-9]{13,15}"
End With
ogrnSearch.setOptions(ogrnOptions)
'--------------------------------------------------------------------------------------------------------------------------
oFound = oRange.GetCellByPosition (0,0) 'инициализация

Do While Not IsNull(oFound)
oFound = oRange.findNext( oFound, oDescriptor)
if Not IsNull(oFound) then

'поиск следующей позиции
nxtFound = oRange.findNext( oFound, oDescriptor)
if isNull (nxtFound) then
nxtFound = openSheet1.getCellByPosition ( oFound.CellAddress.Column, oFound.CellAddress.Row+20)
End if

'поиск ОГРН - цикл заканчивается при нахождениии огрн или когда доходит до следующей позиции
j = oFound.CellAddress.Row-1
Do
j=j+1
ogrnFound = openSheet1.getCellByPosition(3,j)
ogrnSearching = ogrnSearch.searchForward(ogrnFound.String, 0, Len(ogrnFound.String))
Loop while (ogrnSearching.subRegExpressions = 0) and (j <= nxtFound.CellAddress.Row)
end If
Loop

End Sub