Добрый день! У меня проблема со скоростью работы функции Replace LibreOffice Basic.
Sub TestReplace
Dim s as String, i as Long, n as Long, t as Long
n=100000
s=Space(n) & "1"
i=InStr(s, "1") ' мгновенно даже при n=4000000
t=GetSystemTicks
s=Replace(s, " ", "*")
Msgbox "n=" & n & " time=" & (GetSystemTicks-t)
End Sub
При значениях n>=100000 время работы функции увеличивается пропорционально квадрату числа n. При этом функция InStr отрабатывает мгновенно.
Можно, разумеется, воспользоваться соответствующими UNO, но хотелось бы эфффективной работы "родных" функций Basic.
Моя версия: Win 10, LO 6.3.3.2 (x64).
Ну, SbRtl_Replace (https://opengrok.libreoffice.org/xref/core/basic/source/runtime/methods.cxx?r=8b0a6949#1216) оптимизировать-непереоптимизировать.
Цитата: sokol92 от 24 апреля 2020, 20:27У меня проблема со скоростью работы функции Replace LibreOffice Basic.
Цитата: sokol92 от 24 апреля 2020, 20:27При этом функция InStr отрабатывает мгновенно.
Ну, вы сравнили... две большие разницы. Функция
InStr находит подстроку в строке (в вашем примере последний символ в строке состоящей из 100001 символа), а функция
Replace заменяет 100000 пробелов на звёздочки.
Для честного сравнения если
InStr ищет только один последний символ, то и
Replace должна искать и заменять только один последний символ. В этом случае поиск и замена в 2 — 3 раза медленней чем только поиск, что нормально. Проверьте:
Sub TestReplace
Dim s as String, i as Long, n as Long, t as Long
n=100000000
s=Space(n) & "1"
t=GetSystemTicks
i=InStr(s, "1") 'при n = 100 000 000 у меня time=112
Msgbox "i=" & n & " time=" & (GetSystemTicks-t)
t=GetSystemTicks
s=Replace(s, "1", "*") 'при n = 100 000 000 у меня time=293
Msgbox "n=" & n & " time=" & (GetSystemTicks-t)
End Sub
Цитата: mikekaganski от 24 апреля 2020, 22:06
Ну, SbRtl_Replace (https://opengrok.libreoffice.org/xref/core/basic/source/runtime/methods.cxx?r=8b0a6949#1216) оптимизировать-непереоптимизировать.
Это ты тонко
Это исправление (https://gerrit.libreoffice.org/c/core/+/92884) сделает функцию мгновенной.
А пока можете значительно ускорить её, если зададите ей чувствительность к регистру.
Добрый день, коллеги. Спасибо за ответы, и, особенно, за впечатляющую конструктивную реакцию! Подождем версии 7.
Еще пара замечаний в части Replace.
1. Ограничение на максимальное значение 65535 параметра Start, указанное в документации, выглядит явным атавизмом. Правда, этот параметр используется редко.
2. О регистре символов. Тестировал на:
msgbox Replace("Default is binary compare", "BINARY", "Text")
Если присутствует оператор Option VBASUPPORT 1, то производится сравнение с учетом регистра символов (бинарное), иначе без учета регистра символов (текстовое), что, на мой взгляд, логично (соответствует умолчанию VBA). Было бы неплохо указать об этом в документации по функции Replace.
Проверил на вчерашней тест-системе кузину Replace - SUBSTITUTE из семьи Sheet.FunctionAccess.Callfunction. Те же симптомы. Может быть, ее тоже вылечить?
Цитата: sokol92 от 25 апреля 2020, 13:29
1. Ограничение на максимальное значение 65535 параметра Start, указанное в документации, выглядит явным атавизмом. Правда, этот параметр используется редко.
Добавил в tdf#132390 (https://bugs.documentfoundation.org/show_bug.cgi?id=132390).
Цитата: sokol92 от 25 апреля 2020, 13:29
2. О регистре символов. Тестировал на:
msgbox Replace("Default is binary compare", "BINARY", "Text")
Если присутствует оператор Option VBASUPPORT 1, то производится сравнение с учетом регистра символов (бинарное), иначе без учета регистра символов (текстовое), что, на мой взгляд, логично (соответствует умолчанию VBA). Было бы неплохо указать об этом в документации по функции Replace.
Напишите отдельный баг.
Цитата: sokol92 от 25 апреля 2020, 13:29
Проверил на вчерашней тест-системе кузину Replace - SUBSTITUTE из семьи Sheet.FunctionAccess.Callfunction. Те же симптомы. Может быть, ее тоже вылечить?
И этот баг напишите.
Очередное cпасибо! Писать про баги пока еще Заратустра статус не позволяет. ;)
Цитата: sokol92 от 25 апреля 2020, 14:31
Очередное cпасибо! Писать про баги пока еще Заратустра статус не позволяет. ;)
чего чего? Какой ещё статус? вот адрес bugs.documentfoundation.org , заводите учетку и пишите (только на английском пожалуйста). Баг трекер всегда открыт для всех, ни про какие "статусы" я никогда не слышал
Спасибо! И еще вопрос:
s=replace("ABCD","A","B",,,1)
устанавливает в s значение !!br0ken!!
Это - какое-то соглашение разработчиков об обработке исключительных ситуаций, связанных с синтаксисом Basic?
В то же время запись:
s=replace("ABCD","A","B", Compare:=1)
работает штатно.
А это повод для третьего (вашего) бага про эту функцию (я уже свои три написал).
Реально это ошибка неправильной проверки типа переданной переменной. Вы указали ,,, - все пропущенные параметры передаются как объект "ошибка - отсутствующий именованный параметр" (ошибка 448). Функция этого не проверяет, и пытается этот объект превратить в число (получается 448). Попытка вернуть подстроку четырёхсимвольной строки начиная с 448 позиции выдаёт такую ошибку (до моего исправления выше) или пустую строку (после того исправления) вместо того, чтобы эту ошибку считать "используй значение по умолчанию" (1).
Спасибо, как всё, оказывается, интересно! :)
Поменял версию на Win10 LO Версия: 6.4.3.2 (x64).
Третий отмеченный Михаилом баг - некорректная работа с символами юникода из страницы 01 и далее (в частности, с буквами кириллицы).
Посмотрел по ссылке код функции SbRtl_Replace. В строках 1286 и 1287 используется функция (toAsciiUpperCase), которая про юникод ничего не знает (поскольку значительно старше по возрасту). Эта же старушка не дает корректно работать функциям Basic InStr, InStrRev, Strconv (нет в документации), Curdir.
В том же модуле C++ есть функции SbRtl_LCase, SbRtl_UCase, SbRtl_StrComp, которые с юникодом обращаются корректно.
Проверяем корректность работы Instr и InstrRev(только с поддержкой VBA) при работе с кириллицей по сравнению с латынью:
Option VBASUPPORT 1
Sub TestInstr
Dim v
For each v In array("s", "ш")
Msgbox "Instr: text1=" & Ucase(v) & " text2=" & v & " compare=1" & " result=" & _
Instr(1, Ucase(v), v, 1) & chr(10) & _
"InstrRev: text1=" & Ucase(v) & " text2=" & v & " compare=1" & " result=" & _
InstrRev(Ucase(v), v, 1, 1) & chr(10)
Next v
End Sub
Вывод: результаты работы с кириллицей некорректны.
В реализации других функций Basic использование toAsciiUpperCase (toAsciiLowerCase), на мой взгляд, не опасно, поскольку эти функции (обработка даты, времени...) не взаимодействуют с текстом, содержащий символы юникода с кодами >=U+0100
Цитата: sokol92 от 26 апреля 2020, 13:42Третий отмеченный Михаилом баг - некорректная работа с символами юникода из страницы 01 и далее (в частности, с буквами кириллицы).
Вы про tdf#132389 (https://bugs.documentfoundation.org/show_bug.cgi?id=132389)?
Цитата: sokol92 от 26 апреля 2020, 13:42В строках 1286 и 1287 используется функция (toAsciiUpperCase)
... после исправления - в строках 1282 и 1283.
Цитата: sokol92 от 26 апреля 2020, 13:42В реализации других функций Basic использование toAsciiUpperCase (toAsciiLowerCase), на мой взгляд, не опасно, поскольку эти функции (обработка даты, времени...) не взаимодействуют с текстом, содержащий символы юникода с кодами >=U+0100
Ой не факт. Обработка дат вида "5 октября" вполне себе возможна. Ну, и для полноты занудствования - "с кодами >= U+0080".
Вы вполне можете попробовать это всё поправить. Я готов Вам помочь с развёртыванием среды разработки и вопросами по патчам. Мне так кажется, что у Вас всё получится.
Спасибо!