Как стать автором
Обновить

Комментарии 17

Интересует следующий вопрос: храните ли вы в каком-то виде карту зависимостей, чтобы более оптимально определить список ячеек, которые необходимо обновить при изменении значения в одной из ячеек? Если да, то каким образом она у вас представлена, и обнаруживаете ли вы в ней кольцевые ссылки?
Мы как раз сейчас занимаемся улучшением этого механизма.
Зависимости между диапазонами ячеек хранятся в нескольких R-деревьях(для каждого листа), а так же дополнительных деревьях для отдельных ячеек.
При изменении значения ячейки находим по дереву и помечаем на вычисление все зависимые. В памяти так же хранится последовательность ячеек, содержащих формулы. Эта последовательность может меняться при вычислении и со временем приобретает упорядоченный вид(каждая ячейка зависит только от уже посчитанных предыдущих). Во время вычисления отслеживаем перемещения ячейки по списку. Если ячейке пришлось переместиться более одного раза — то в этой ячейке содержится циклическая ссылка. Такие ячейки пропускаем и считаем дальше до конца списка. Затем, если включены итеративные вычисления, отдельно считаем все выделенные ячейки требуемое количество раз.
Возможно со временем напишу отдельную статью про это — там много интересного, на мой взгляд.
А как вы боретесь с тем что у экселевских операторов в офисных пакетах на разных языках разные названия и даже синтаксис?
К примеру объединение строк в английском пакете CONCAT а в немецком VERKETTEN + разделитель между переменными ещё и зависит от локали т.е. теоретически вообще непрогнозируем если кто-то у себя настроит в системе, что разделителем дробной части числа является скажем знак вопроса итд итп
При установке текущей локали в настройках контрола мы заполняем словарики с локализованными именами функций и ошибок.
А так же берем текущие ListSeparator и DecimalSeparator.
Сканер и парсер изначально настроены на дефолтные настройки. При инициализации сканера подсовываем разделители в карту начальных состояний и в читающий автомат.
Парсер на этапе разбора выражения выделяет имена функций и по имени ищет экземпляр класса функции в локализованном списке. В модели данных хранится не уже не имя функции, а ее код. При необходимости построить выражение в строку из RPN, имя функции берется из локализованного словаря уже по коду.
На данный момент есть локализации имен функций и ошибок для 20 языков. Если контрол еще не переведен на нужный язык, пользователи пользуются сервисом localization.devexpress.com, где могут добавить собственный перевод.
Да, именованные формулы тоже поддерживаются.
Проверяли ли вы работу со специфическими файлами, например, большого размера и/или с огромным количеством сложных глубоких формул с множеством преобразований типов данных? Сравнивали скорость работы вашего контрола и разбора формул со скоростью XL для тех же задач?

Вообще, мне кажется, тестирование подобного функционала — это весьма интересная тема. Наверняка, вы не только вычисляете свои результаты формул и сравниваете их с исходными. Что и как еще вы тестируете?
Количество преобразований типов данных в формуле — не критичный параметр с точки зрения производительности. Самая большая потеря производительности происходит при вычислении функций, просматривающих большой диапазон ячеек(например, LOOKUP, SUMIF и т.д.) — их периодически пробуем ускорить.
Из общего набора файлов выделили те, что содержат большое количество формул. На этих файлах ежедневно запускается анализ производительности. По результатам делаем выводы.
Кроме тестов на вычисление тестируем построение дерева зависимостей между ячейками, импорт файлов, конвертируем документ из одного формата в другой. Тестируем записанные нами файлы при помощи Excel и сторонних утилит.
Все это делается одним приложением, которое запускается на тестовой ферме с разными параметрами.
Вы упоминаете, что:
> «Выражение в Excel хранится в обратной польской записи»
и
> «Excel, еще на этапе разбора выражения, старается облегчить себе дальнейшую жизнь. Для этого он, по возможности, наполняет выражения всяческими вспомогательными элементами.»
Эта информация из документации и открытых источников или вы каким то образом изучили dll от MS, или reverse engineering?
Большая часть этой информации получена в ходе изучения документации по бинарному формату xls. В него выражения записываются в RPN.
Это название опять же из документации по xls. Там, правда, в основном используется сокращение Ptg.
если не секрет, какие «сторонние утилиты» используете для проверки вычислений?
Рекомендую посмотреть на Apache POI. Там довольно мощный эвалюатор формул. Поддерживается большая часть синтаксиса и формул.
Мы не используем сторонние утилиты для проверки вычислений. Мы сравниваем результаты расчета каждой ячейки со значением, прочитанным из исходного файла. Большинство этих файлов рассчитано и записано Excel'ем. Встречались файлы с неверными значениями, но их было не много. Все такие файлы мы проверяли вручную и добавляли при необходимости исключения, чтобы в следующий раз конкретная ячейка не проверялась.
Здравствуйте, как вы знаете, существует порт под платформу .Net — NPOI. Я смотрел версию 2.0 beta 1. Парсер строковых выражений не поддерживает некоторый тип ссылок (интервал колонок), имена функций с точкой (STDEV.P). Реализовано меньше половины известных POI функций. Написав тест на несколько поддерживаемых функций, результат не совпадал с Ms Excel. Расчет формул, используя внешние ссылки не реализован. Не реализован расчет array-функций. Ссылки на части таблицы тоже не считаются. Самым неочевидным стало, что заданная формула в HSSFWorkbook не сохраняется в документе, а сохраняется только значение.
Как вы высоту строки и ширину столбца рассчитываете?
Слышал, что ширина в «символах» измеряется.

Как вы реализовали поддержку мультиязычности функций(SUM-СУММ)?
Да, Вы правы, ширина меряется в «символах». В спецификации OpenXML приведен алгоритм пересчета.
По поводу локализации имен функции есть ответ чуть выше.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий