Обносление испортило формулы

Автор Kadet, 8 декабря 2021, 11:31

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

Kadet

Вчера поставил обновление LO 7.2.4.1

После этого часть формул, создаваемых макросом в листе calc, стали выдавать ошибку.
Причём как-то странно - в одних случаях формула продолжает работать с других нет.

Вот такую формулу создаёт макрос (oVK = 5 (intager)):
oSheet.getCellByPosition(14, oRow).setFormula("=C701*" & oVK/100)
Она перестала работать.

Нашёл такой выход, как всегда обходной:
oSheet.getCellByPosition(14, oRow).setFormula("=C701*" & oVK & "/100")

Эта формула прекращает работать в тех случаях если используется формат ячейки C701 с разделителями разрядов тысяч и если это значение больше тысячи (т.е. появляется пробел между тысячами и пр.). Пока число меньше тысячи формула работает. Появляется пробел разделителя - появляется ошибка "=#ИМЯ".

Регресс, однако.

mikekaganski

Это не регресс, а прогресс. Конкретно - это исправление бага 97983, где раньше простое приведение числа к строке не использовало параметры локали.

Раньше было так:

  dim s as string
  dim d as double
  d = 1.5
  s = d ' s = "1.5" независимо от текущей локали!!!
  d = s ' d = 1.5 в локали en-US, и d = 1 в локали ru-RU, потому что в последней превращение строки в число правильно использовало локаль!


Теперь:

  dim s as string
  dim d as double
  d = 1.5
  s = d ' s = "1.5" в локали en-US, и s = "1,5" в локали ru-RU
  d = s ' d = 1.5


При этом, как и раньше, локаль-независимые преобразования строк в числа и обратно должны производиться с помощью функциq Val/Str. См. руководство по Basic.

А setFormula как раз и устанавливает локаль-независимую формулу, и поэтому все числовые литералы там должны использовать точку.

oSheet.getCellByPosition(14, oRow).setFormula("=C701*" & Str(oVK/100))
С уважением,
Михаил Каганский

Kadet

#2
Интересненький "прогресс".
То, что были проблемы с локалями это факт. Из-за неё мне часто приходится в своих макросах испрользовать подмены типа
var = replace(var1,",",".")

Если это исправлено, то это прекрасно.

Однако, странное дело таки с этим "прогрессом".
Простая матемематическая формула - oVK/100, перестала работать.
Причём действительно в совокупности с разделителями тысяч.
Засомневался в своей версии про разделители, ведь исправление "oVK/100" на "oVK & "/100"" дало положительный результат, а оно меняет разделители дробной части, а не тысячные.
В общем, попробовал проверить так:
Dim dVK#
dVK = oVK/100
oSheet.getCellByPosition(14, oRow).setFormula("=C701*" & dVK)

Не алё. Результат - ошибка.

Если после формирования страницы calc вручную обновить ссылку на ячейку C701, при первичном варианте формулы (т.е. - ""=C701*" & oVK/100"), то ошибка уходит.

Вариант с "Str(oVK/100)" работает.

Однако, странное "улучшение", с усложнением.

Нужно ещё проверять не испортились ли формулы в других местах программы. Пока выявил в одном месте, но из же гораздо больше.

mikekaganski

#3
Цитата: Kadet от  8 декабря 2021, 12:53В общем, попробовал проверить так:

Ну ок, я понял, что не было смысла приводить правильный вариант строки Basic и объяснять, раз это всё игнорируется.

Цитата: Kadet от  8 декабря 2021, 12:53То, что были проблемы с локалями это факт.

Но то, что Вы привели как "проблемы с локалями", является просто неумением работать с ними.
С уважением,
Михаил Каганский

Kadet

#4
"Правильный вариант", насколько я понимаю, был проверен и подтверждён, и даже отзыв об этом описан. Не так?
Просто ДО появления "правильного" варианта были проведены тесты других вариантов. Что и описано.

Однако, что скрывается за:
Цитата: mikekaganski от  8 декабря 2021, 13:00является просто неумением работать с ними
?

Когда я беру данные из ячейки calc, где по локали дробное число представляется через запятую, и пытаюсь его засунуть в БД, у которой по умолчанию и неизменно разделитель дробной части является точка и ничто другое, в итоге получаю ошибку, пока не проведу replace переменной с переводом её в Str.
В чём "неумение"?

mikekaganski

Я уже описал: для локаль-зависимых преобразований используются одни методы, для независимых - другие. Даже ссылку дал на документацию. Использование replace для этого неправильно.
С уважением,
Михаил Каганский

Kadet

Да даже любое математическое получение дробного числа типа doeble в макросе, допустим как результат математической функции, тоже приходится прогонять через replace чтобы подать его в SQL запрос.

Kadet

#7
Цитата: mikekaganski от  8 декабря 2021, 13:18...зависимых преобразований...
...независимых...
Для меня это абракадабра. Не понимаю о чём речь. Со ссылкой и без неё - не понимаю. Тем более в английской версии.

Kadet

#8
Чего уж тут понимать?
Раньше функция Str в принципе не работала.
Поэтому всеми силами старался её избегать или обходить с финдиперсами. Много крови попила.
Зато простая банальная "неправильная" математика внутри формулы, как -то (""=C701*" & oVK/100") - работала и кушать не просила.

А теперь... всё наоборот.
Теперь, однако, без Str уже не обойтись.

mikekaganski

#9
Когда Вы работаете с числами и строками, первое, что необходимо понять - это что число может быть представлено разными строками, а разные строки, представляющие одно и то же число, могут быть по-разному восприняты в разных случаях. Это связано с богатой историей человечества, письменности, математической записи и других увлекательных вещей. В принципе это всё зависит от локали (то есть от соглашений по представлению данных, принятых в данной местности или в данной ситуации).

Понимание этого приводит нас к понятию текущей локали. Обычно это то, что представляется "обычным/нормальным" простому пользователю Вашей программы: например, использование запятой для разделения дробной части в России. В Basic стандартные преобразования все задуманы использующими именно текущую локаль - то есть все стандартные преобразования должны в России считать дроби отделяющимися запятой.

Однако при программировании имеется множество вещей, которые не должны зависеть от локали. Например, если Вы формируете формулы и будете их писать для Вашей русской локали, с использованием русских названий функций и т.п., то программа не будет работать в других локалях. Поэтому программист должен думать о том, в каком месте программы у него данные в текущей локали, а в каком - должны быть независимы от текущей локали. Это основы, без этого понимания всегда возникают проблемы.

В ЛО был баг, что стандартное преобразование числа в текст всегда использовало "стандартную" локаль en-US, а стандартное преобразование текста в число - текущую локаль. Это было несоответствие документации и дизайну. Это и было исправлено. А для приобразования любого числа в стандартный вид (независимо от локали в строку с использованием точки для разделения целой и дробной частей) - всегда были функции Str и Val. Надо преобразовать строку, введённую пользователем, в число - используем стандартное преобразование (просто присваиваем строку числовой переменной). Надо взять число из базы данных, где числа в стандартной форме - используем Val(s). Надо число показать пользователю - используем стандартное преобразование (например, просто передаём число в MsgBox), что даст привычный для пользователя вид. Надо число засунуть в формулу Calc, где используется стандартный вид - используем Str(n).

Ну и всегда для преобразований с использованием локали (то есть вместо стандартных преобразований) можно было использовать функции CStr/CInt/CDbl/...

То, что Вы полагались на нестандартное, ошибочное поведение в одних местах, и страдали от того же самого в других - это и был баг, который полностью рушил логику  преобразований. Исправление ничего не усложнило. Если бы Вы использовали Str/Val/CStr/CDbl... везде, где данные преобразуются между типами (число-строка), Вы даже не заметили бы ничего.

А использовать replace для того, что Вы делаете - нельзя, потому, например, что в некоторых локалях запятая - это разделитель тысяч.
С уважением,
Михаил Каганский

mikekaganski

Цитата: Kadet от  8 декабря 2021, 13:41Раньше функция Str в принципе не работала

Это когда она не работала?
С уважением,
Михаил Каганский

Kadet

#11
Цитата: mikekaganski от  8 декабря 2021, 14:04Это когда она не работала?
Это когда при d=1,5 она делалось d = 1.
А зачастую просто давала ошибку. Приходилось от неё избавляться. И началось это не так давно.
В общем пришлось выискивать и проверять все входы этой функции.
В общем, с какого-то времени я стал избегать и даже побаиваться этой Str.

А теперь - всё наоборот.

Спасибо за лекцию, но всё это понятно и известно. Мне в принципе не понятно какие математические функции могут быть независимы от локали. Разве что 1+1.

Мне больше не понятно почему перестала работать вариация "на свободную тему" - "=C701*" & oVK/100. По сути я передаю ячейке строку "=C701* плюс числовое дробное значение - (допустим = 0,05), как результат вычисления - oVK/100. И я не заморачивался с переводом в Str и с локалями. И транслятор Bacic сам всё это переводил в удобный для себя формат... и это работало.
И теперь, почему-то, транслятору нужно "чётко говорить" - "переведи в Str", хотя раньше это было излишним.

mikekaganski

Ох.

Вы не понимаете, чем число 0,1 отличается от строки "0,1"?
С уважением,
Михаил Каганский

Kadet

Если мне не изменяет память, то любое число типа double, при переводе через Str выбивало ошибку. Точно не помню с когда это началось. Возможно с выходом 7-ки, но не буду утверждать.
Почему помню и говорю об этом? Потому что во многих своих SQL-запросах для занесения данных типа double в базу мне постоянно приходилось использовать подобный конструкт:
Replace(Str(oSheet.getCellByPosition(14, oRow).getValue()), ",", ".")
И таких "приколов" было просто тьма.

А потом, в каокй-то момент всё пришлось переписывать и убирать все упоминания Str, ибо при каждом её упоминании неизменно давало ошибку.

Kadet

#14
Цитата: mikekaganski от  8 декабря 2021, 14:57Вы не понимаете, чем число 0,1 отличается от строки "0,1"?
Понимаю.
Только не понимаю почему раньше транслятор сам переводил число, результат вычисления oVK/100 (т.е. число 0,05), в строку, переводя это в удобный для себя формат (по сути в 0.05 - с точкой), а теперь перестал. И теперь ему для этого потребовались конкретные указания программиста - "Str(oVK/100)"