Vba excel нельзя установить свойство formulaarray класса range

 

Probabiz

Пользователь

Сообщений: 3
Регистрация: 11.01.2020

Здравствуйте!
Помогите пожалуйста с формулой массива. С макросами работаю 2й день, в общем опыта работы с макросами нет. Но хотел бы разобраться в текущей ошибке Run-time error ‘1004’: Нельзя установить свойство Formulaarray для класса Range.
Пробывал разбивать на несколько формул общую, так как общая формула больше 255 символов, но не помогло, возможно, что-то неправильно сделал.
Могли бы вы посмотреть формулу и указать на ошибку, или в какую сторону дальше ковырять.
Прикладываю часть массива и кода

Прикрепленные файлы

  • пример.xlsm (20.79 КБ)

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

Probabiz, Не совсем понятен вопрос.  Действительно вставить макросом формулу длиннее 255 не получится в случае если это массивная. Существует 4 метода
1. вставить как обычную, а потом симулировать CTRL+SHIFT+ENTER
2. сперва вставить формулу массива не полную, но работающую, а потом заменой заменить её часть , сделав её полной.
3. Использовать формулу в именах и на лист помещать уже имя
4. Sokol92 демонстрировал функцию, которая автоматом итерациями разбирала вложения и делала соответствующие замены, что аналогично №2 но не требует искать что на что можно заменить.

Ну и 5. сократить саму формулу — было 154
=IFERROR(LOOKUP(SUMPRODUCT((ISNUMBER(SEARCH(CHAR(42)&Заявка!C3&CHAR(42);Прайс!$C:$C)))*(Прайс!$F:$F=Заявка!J3);Прайс!$A:$A);Прайс!$A:$A;Прайс!$D:$D);»»)
. Вот нафига там CHAR(42) если это «*», вроде не много а 5 символов экономим.  ссылаться на ячейку того же  листа можно без именини листа,  Закрепленные столбцы не нужны
=IFERROR(LOOKUP(SUMPRODUCT((ISNUMBER(SEARCH(«*»&C3&»*»;Прайс!C:C)))*(Прайс!F:F=J3);Прайс!A:A);Прайс!A:A;Прайс!D:D);»»)
, а вот то что диапазон  — полный столбец — это некорректно нужно указывать с ограничением строк иначе страдает быстродействие. Правда мы тем самым раздуем опять формулу, но тут придут на помощь именованные диапазоны, замените  
диапазоны на имена Прайс!A$1:A$1000 на_PrA занеся в имена.
=IFERROR(LOOKUP(SUMPRODUCT((ISNUMBER(SEARCH(«*»&C3&»*»;_PrC)))*(_PrF=J3);_PrA);_PrA;_PrD);»»)
стало 95
Аналогично с длинной.
=IF(IFERROR(LOOKUP(SUMPRODUCT((ISNUMBER(SEARCH(«*»&C3&»*»;_PrC)))*(_PrF=J3);_PrA);_PrA;_PrG);»»)=0;»»;IFERROR(LOOKUP(SUMPRODUCT((ISNUMBER(SEARCH(«*»&C3&»*»;_PrC)))*(_PrF=Заявка!J3);_PrA);_PrA;_PrG);»»))

Изменено: БМВ11.01.2020 14:46:03

По вопросам из тем форума, личку не читаю.

 

skais675

Пользователь

Сообщений: 2177
Регистрация: 03.06.2014

А где же лист КоммунСервис?

Изменено: skais67511.01.2020 14:16:21

 

Probabiz

Пользователь

Сообщений: 3
Регистрация: 11.01.2020

#4

11.01.2020 14:24:22

Это я не доподчистил файл, пропустил. Лист переименован на «заявка»

БМВ, а как симмулируется CTRL+SHIFT+ENTER?

Цитата
БМВ написал: …придут на помощь именованные диапазоны, замените  диапазоны на имена Прайс!A$1:A$1000 на_PrA занеся в имена.

Это с помощью операторов DIm и Replace правильно понимаю?

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

Probabiz,  Просто сперва измените формулу см. пример. Потом сможете взять образец для макроса.
По поводу симуляции
Нужну симулировать через

application.sendkeys

для ячейки активной F2 и CTRL+SHIFT+ENTER

посмотрите

https://www.planetaexcel.ru/forum/index.php?PAGE_NAME=read&FID=1&TID=118970

и

http://www.excelworld.ru/forum/10-42409-1

Изменено: БМВ11.01.2020 15:09:44

По вопросам из тем форума, личку не читаю.

 

Probabiz

Пользователь

Сообщений: 3
Регистрация: 11.01.2020

#6

11.01.2020 16:23:06

Цитата
БМВ написал: Нужну симулировать через  application.sendkeys …

БМВ, спасибо за подсказки и напутствия! Все формулы укоротил, как Вы и говорили с помощью диспетчера имен. И ошибка Нельзя установить свойство Formulaarray для класса Range пропала. Все заполняется как надо.
Но изначально почему начал переводить все формулы в макросы, из-за того что таких прайсов 6 штук по 50000 строк, и заявка на 500 строк, в общем вычисления производятся очень долго от 30 минут до 1,5 часа в зависимости от компьютера.
Благодаря Вам сейчас все формулы заполняет макрос, но вставляет формулы а как сделать так чтобы он вставлял значения, или как вообще ускорить процесс вычисления?

 

skais675

Пользователь

Сообщений: 2177
Регистрация: 03.06.2014

Probabiz Исходя из вышесказанного, нужно было все макросом сделать используя массивы — а это совсем другая тема.

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

#8

11.01.2020 17:01:59

Цитата
Probabiz написал:
30 минут до 1,5 часа

это было из-за использования целых столбцов. Убежден, что сейчас будет в десятки раз быстрее, даже если в именах заменить 10000 на 60000 или даже 10000.
Если к этому добавить неоптимальный формулы, то ….. например цена преображается в
=IFERROR(1/(1/SMALL(IF(ISNUMBER(SEARCH(«*»&C3&»*»;_PrC));_PrF;»»);I3));»») обратите внимание, что не простая функция SMALL применится один раз
да и длинная становится вот такой и не массивной
=IFERROR(1/(1/LOOKUP(SUMIFS(_PrA;_PrC;C3;_PrF;J3);_PrA;_PrG));»»)
то даже можно вернуть диапазоны из имен обратно, а скорость вас удивит.

Цитата
skais675 написал:
а это совсем другая тема

— да тема другая, но как обычно сперва фундамент надежный, а потом дом, а тут фундамент подкачал, каков бы технологичный дом небыл — рухнет, что собственно и происходило.

Прикрепленные файлы

  • Copy of пример1396_1.xlsm (18.14 КБ)

Изменено: БМВ11.01.2020 17:06:50

По вопросам из тем форума, личку не читаю.

 

Кирилл Журенко

Пользователь

Сообщений: 4
Регистрация: 30.01.2021

#9

30.01.2021 19:47:08

Добрый день! Дабы не плодить темы, решил спросить здесь. Ошибка та же, что и у ТС. Но у меня проблема не в длинной формуле, а в чем-то другом, никак не могу понять.
Вот такая строчка работает:

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=СУММ(ЛЕВСИМВ(" & SSRange(k, i) & ")"

А вот такая уже нет:

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=СУММ(ЛЕВСИМВ(" & SSRange(k, i) & ";1))"

SSRange — диапазон в виде строки типа «A3:A6». Если вводить в ячейку эту формулу вручную, не через VBA, то все работает.
Гуглить по этой проблеме уже замучился, в основном проблема у всех с длиной больше 255 символов. Помогите, пожалуйста, разобраться.

Изменено: 0rtega30.01.2021 20:34:32

 

sokol92

Пользователь

Сообщений: 4445
Регистрация: 10.09.2017

#10

30.01.2021 20:47:26

Цитата
Кирилл Журенко написал:
Вот такая строчка работает

Сомневаюсь. Свойство FormulaArray не локализовано, должны быть «американские» имена функций и  разделители.

Владимир

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

#11

30.01.2021 20:50:37

Цитата
Кирилл Журенко написал:
Добрый день! Дабы не плодить темы, решил спросить здесь.

и это не правильно

По вопросам из тем форума, личку не читаю.

 

0rtega

Пользователь

Сообщений: 4
Регистрация: 30.01.2021

#12

30.01.2021 21:18:13

Цитата
sokol92 написал:
Сомневаюсь. Свойство FormulaArray не локализовано, должны быть «американские» имена функций и  разделители.

Напрасно, можете проверить и убедиться сами. За подсказку про локализацию спасибо, исправил, однако результат тот же. На строке:

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=SUM(VALUE(LEFT(" & SSRange(k, i) & ";1)))"

выдается та же ошибка.

Цитата
БМВ написал:
и это не правильно

Первый раз такое на форумах встречаю. На всякий случай уточню: мне следует создать аналогичную тему с тем же вопросом, что и у ТС, и описать свою ситуацию? И ее не удалят в связи с пунктом 3.7 Правил?

Изменено: 0rtega30.01.2021 21:19:37

 

БМВ

Модератор

Сообщений: 21378
Регистрация: 28.12.2016

Excel 2013, 2016

#13

30.01.2021 21:35:55

просто у вас вопрос синтаксиса, а именно , разделитель ; должен быть в VBA ,

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=SUM(VALUE(LEFT(" & SSRange(k, i) & ",1)))"

а можно

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=SUM(VALUE(LEFT(" & SSRange(k, i))))"

или

Код
Myregionnew(ArrayofSS(k), i).FormulaArray = "=SUM(--LEFT(" & SSRange(k, i)))"

По вопросам из тем форума, личку не читаю.

 

0rtega

Пользователь

Сообщений: 4
Регистрация: 30.01.2021

#14

30.01.2021 22:02:34

Цитата
БМВ написал:
просто у вас вопрос синтаксиса, а именно , разделитель ; должен быть в VBA ,

Заработало! :)  Спасибо большое! Получается, это справедливо только для FormulaArray? До этого в обычных формулах (FormulaLocal) в VBA всегда использовал точку с запятой, никогда проблем не возникало…

Изменено: 0rtega30.01.2021 22:07:17

 

Вы не обращали внимания на то, что тут ключевое — Local. Т.е. формула должна вводиться в той локализации, которая применена в Excel и формула будет работать. А в FormulaArray у Вас где Local? Нигде. А значит надо вводить на «интернациональном» для VBA языке и по его правилам. А этот английский с разделителем аргументов запятая.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

0rtega

Пользователь

Сообщений: 4
Регистрация: 30.01.2021

Дмитрий(The_Prist) Щербаков, спасибо большое за разъяснение

 

Дмитрий(The_Prist) Щербаков

Пользователь

Сообщений: 14182
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#17

31.01.2021 10:29:35

Цитата
0rtega написал:
Для FormulaLocal в VBA в качестве разделителей допускается указывать только точки с запятой

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

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

Как ввести формулу массива, длиной >256 знаков через VBA

adamm1603

Дата: Среда, 17.07.2019, 15:56 |
Сообщение № 1

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

Всем привет!
Сломал голову, прочитал кучу информации, но ни как не могу найти решение. На одном из форумов есть решение перенести код на другую строчку, с помощью [vba][/vba], но не выходит выдает ошибку: «нельзя установить свойство FormulAarray класса Range». Вообще это возможно?

К сообщению приложен файл:

2500303.xlsm
(22.3 Kb)

 

Ответить

bmv98rus

Дата: Среда, 17.07.2019, 16:12 |
Сообщение № 2

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

adamm1603

Дата: Среда, 17.07.2019, 16:40 |
Сообщение № 3

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

Вариант с именами, не совсем подходит я про него знаю, так как данные формулы массива я вставляю с другой книги, в книгу с тремя листами, на каждом по 14 формул итого 14*3=42 формулы, то есть 42 тмени, на сколько знаю для 32 разрядного офиса это тяжеловато, если я не прав поправьте меня

 

Ответить

bmv98rus

Дата: Среда, 17.07.2019, 16:59 |
Сообщение № 4

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

adamm1603, 42 — даже для 16ти разрядного не много.
ох не люблю я подобные методы
[vba]

Код

Sub Макрос7()

‘ Макрос7 Макрос


    Selection.Formula = _
        «=IF(RC[21]<>»»»»,IF(AND(RC[-1]<>»»»»,IFERROR(LEFT(RC[22],SEARCH(«»/»»,RC[22],1)-1),RC[22])=»»РД»»,RC[28]<>»»»»),SUM((CONCATENATE(RC[28],IFERROR(LEFT(RC[22],SEARCH(«»/»»,RC[22],1)-1),RC[22]))=(РАД_РД[Клеймо сварщика]))*(РАД_РД[начало]<RC[21])*(РАД_РД[окончание]>RC[21]))=0,FALSE),IF(AND(RC[-1]<>»»»»,IFERROR(LEFT(RC[22],SEARCH(«»/»»,RC[22],1)-1),RC[22])=»»РД»»,RC[28]<>» & _
        «»»»»),SUM((CONCATENATE(RC[28],IFERROR(LEFT(RC[22],SEARCH(«»/»»,RC[22],1)-1),RC[22]))=(РАД_РД[Клеймо сварщика]))*(РАД_РД[начало]<RC[20])*(РАД_РД[окончание]>RC[20]))=0,FALSE))»
    SendKeys («{F2}»), True
   SendKeys «^+~», True
End Sub

[/vba]


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusСреда, 17.07.2019, 17:30

 

Ответить

adamm1603

Дата: Среда, 17.07.2019, 17:54 |
Сообщение № 5

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

bmv98rus, спасибо, но при вставке кода, формула массива не закрепляется, нет фигурных скобок

 

Ответить

bmv98rus

Дата: Среда, 17.07.2019, 18:01 |
Сообщение № 6

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

не знаю, у меня все работает


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

adamm1603

Дата: Среда, 17.07.2019, 18:15 |
Сообщение № 7

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

С вашего файла открыл, то же самое, может у меня офис русскоязычный?
Если я правильно понял, сначала формула вставляется, без массива, а после оператор SendKeys заключает фигурные скобки, то есть массив

Сообщение отредактировал adamm1603Среда, 17.07.2019, 18:22

 

Ответить

bmv98rus

Дата: Среда, 17.07.2019, 18:40 |
Сообщение № 8

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Посмотрите что после вставки и проделайте руками F2, Ctrl+Shift+Enter


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

adamm1603

Дата: Среда, 17.07.2019, 18:55 |
Сообщение № 9

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

суть то в том, что ручками я не хотел делать, сама задумка того, что бы исключить ручной ввод

 

Ответить

bmv98rus

Дата: Среда, 17.07.2019, 19:46 |
Сообщение № 10

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Я пишу о том как проверить, а не ….


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

anvg

Дата: Среда, 17.07.2019, 23:14 |
Сообщение № 11

Группа: Друзья

Ранг: Ветеран

Сообщений: 581


Репутация:

271

±

Замечаний:
0% ±


2016, 365

не знаю, у меня все работает

Привет, Михаил.
А зачем же так жестоко?

Цитата

SendKeys («{F2}»), True
SendKeys «^+~», True

А почему бы не использовать [url=https://docs.microsoft.com/ru-ru/office/vba/api/excel.range.formulaarray?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev11.query%3FappId%3DDev11IDEF1%26l%3Dru-RU%26k%3Dk(vbaxl10.chm144133)%3Bk(TargetFrameworkMoniker-Office.Version%3Dv16)%26rd%3Dtrue]Range.FormulaArray property (Excel)[/url]?

 

Ответить

bmv98rus

Дата: Четверг, 18.07.2019, 07:42 |
Сообщение № 12

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

anvg, Андрей, только из-за этого:
Remarks
The FormulaArray property also has a character limit of 255.
.
Собственно что и послужило предпосылкой к появлению темы.


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusЧетверг, 18.07.2019, 07:43

 

Ответить

adamm1603

Дата: Четверг, 18.07.2019, 08:03 |
Сообщение № 13

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

bmv98rus, я разобрался с функцией SendKeys, она имитирует ручной ввод нажатия клавиш, но походу не срабатывает F2, ок буду пробовать ещё спасибо!
F2 срабатывает, но ввод ctrl+shift+enter ни в какую не хочет работать

Сообщение отредактировал adamm1603Четверг, 18.07.2019, 08:36

 

Ответить

bmv98rus

Дата: Четверг, 18.07.2019, 08:33 |
Сообщение № 14

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Непредcказуемый результат — это и есть причина по которой этот метод не лучший. Но если он единственный, то …


Замечательный Временно просто медведь , процентов на 20.

Сообщение отредактировал bmv98rusЧетверг, 18.07.2019, 09:41

 

Ответить

adamm1603

Дата: Четверг, 18.07.2019, 08:48 |
Сообщение № 15

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

Все разобрался SendKeys не хочет работать с 32 разрядной версией офиса

 

Ответить

bmv98rus

Дата: Четверг, 18.07.2019, 09:43 |
Сообщение № 16

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

SendKeys не хочет работать с 32 разрядной версией офиса

значит не разобрались , ибо на 2013×32 это писалось и разницы в разрядности нет. А вот настройки или что-то иное, что перехватывает F2 может быть причиной.


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

adamm1603

Дата: Четверг, 18.07.2019, 11:02 |
Сообщение № 17

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

Я пробовал на 64 офисе работает на 32 нет, возможно совпадение, значит буду копать дальше

 

Ответить

bmv98rus

Дата: Четверг, 18.07.2019, 12:01 |
Сообщение № 18

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

Я пробовал на 64 офисе работает на 32 нет

Думаю вы пробовали не переустанавливая его, а использовали другой ПК, а значит другие настройки другое окружение…… Короче, если все норм, то должно работать, но гарантии 100 нет и нужно проверят Range.HasArray. Что делать если не- Ваше дело, но при наличии таких сложностей, я б использовал имена и количество в сотню не будет проблемой, при этом можно использовать переменную листа а не книги и тем самым использовать три раза одно наименование для разных листов, но одинаковой формулы.


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

adamm1603

Дата: Четверг, 18.07.2019, 15:41 |
Сообщение № 19

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 144


Репутация:

0

±

Замечаний:
0% ±


Excel 2013

 

Ответить

bmv98rus

Дата: Четверг, 18.07.2019, 15:52 |
Сообщение № 20

Группа: Друзья

Ранг: Участник клуба

Сообщений: 4009


Репутация:

760

±

Замечаний:
0% ±


Excel 2013/2016

adamm1603, ну в одной из них я тоже встрял, так что знаю. другое дело что тут обсуждается вопрос на который я дал ответ, более менее рабочий

копируя формулу с одного листа и всавляя в имена, не получается

это другой вопрос Приводите пример в другой теме разберемся. Надеюсь брали формулу FormulaR1C1 для копирования.


Замечательный Временно просто медведь , процентов на 20.

 

Ответить

I’ve created the following formula:

=IFNA(LOOKUP(10^99,--MID(O2,MIN(IF((--ISNUMBER(--MID(O2,ROW($1:$25),1))=0)*ISNUMBER(--MID(O2,ROW($2:$26),1)),ROW($2:$26))),ROW($1:$25))),SUMPRODUCT(MID(0&RIGHT(N2,4),LARGE(INDEX(ISNUMBER(--MID(RIGHT(N2,4),ROW($1:$25),1))* ROW($1:$25),0),ROW($1:$25))+1,1)*10^ROW($1:$25)/10))

It looks at column «N» and bring through just the number string. If there is an N/A it will then do the same on column «O» which is ran as an array and it works fine.

Yet when I converted it to VBA code, I get the error mentioned in the title .

Range("L2").Select
    Selection.FormulaArray = _
        "=IFNA(LOOKUP(10^99,--MID(RC[3],MIN(IF((--ISNUMBER(--MID(RC[3],ROW(R1:R25),1))=0)*ISNUMBER(--MID(RC[3],ROW(R2:R26),1)),ROW(R2:R26))),ROW(R1:R25))),SUMPRODUCT(MID(0&RIGHT(RC[2],4),LARGE(INDEX(ISNUMBER(--MID(RIGHT(RC[2],4),ROW(R1:R25),1))* ROW(R1:R25),0),ROW(R1:R25))+1,1)*10^ROW(R1:R25)/10))"

What it going wrong?

How to enter FormulaArray with over 255 characters using VBA

It seems that, in this case, there was an alternate Standard Formula that complied with the requirements of the original FormulaArray. However, there might be cases for which there is not an alternate formula.
For those cases, I have the following method to enter FormulaArray with over 255 characters using VBA.

Most of the time when a FormulaArray is longer than 255 characters is due to the length of the references it contains, as they may relate to long constant arrays, external workbooks with large names (like in this case) or worksheets with large names (also in this case). The method consist in replacing these long strings with shorter ones, however in order for the FormulaArray (after replacement) to be accepted as a FormulaArray those shorter strings need to also represent valid references.

As per the above, there could be, at least, three situations with long references:

  1. Long constant arrays: In these cases use Defined Names as described here

https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7

  1. Workbooks with large names and
  2. Worksheets with large names

For cases 2 and 3 same method applies: The use of short references pointing to a temporary Worksheet as temporary replacement.

Applying the method to this case:

Original FormulaArray: use variable sFmlArray to hold the formula

Dim sFmlArray As String
sFmlArray = "=INDEX('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!AK:AK," & _
    "MATCH(1,('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$A:$A = A" & bVal & ") * " & _
    "('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$B:$B=""Total""),0)) * 1000"

I suggest the use of variables to hold the names of the workbook and worksheet in order to avoid having to write them several times.

Dim sFmlRng as string
sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

Replace the names of the workbook and worksheet in the FormulaArray with the corresponding variable:

sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
    "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
    "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

Assuming we want to enter this long FormulaArray in the range D7:D10, let’s assign it to a variable

Dim rFmlAry as Range
Set rFmlAry = ActiveSheet.Range("D7:D10")

Use the function below to add the temporary worksheet. This function also provides the temporary reference to be used as replacement in the FormulaArray

Function WshTmp_Add(rFmlAry As Range, sFmlRngTmp As String) As Worksheet
    sFmlRngTmp = "@Tmp"
    With rFmlAry.Worksheet.Parent
        On Error Resume Next
        .Worksheets(sFmlRngTmp).Delete
        On Error GoTo 0
        Set WshTmp_Add = .Worksheets.Add(Before:=.Worksheets(1))
    End With
    WshTmp_Add.Name = sFmlRngTmp
    WshTmp_Add.Tab.Color = 255
    sFmlRngTmp = "'" & sFmlRngTmp & "'!"
    Application.Goto rFmlAry
End Function

Replace, in the FormulaArray, the long references with the shorter one and enter the temporary FormulaArray in the rFmlAry range

sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)
rFmlAry.FormulaArray = sFmlAryTmp

With the FormulaArray in place, replace the temporary short references with the original long ones

rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
    LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
    SearchFormat:=False, ReplaceFormat:=False

Finally delete the temporary Worksheet

This is the entire procedure (as a test, added few lines at the end to validate the result)

Sub FormulaArray_Over255Chr()
Dim rFmlAry As Range, sFmlAry As String, bVal As Byte

Dim WshTmp As Worksheet, sFmlAryTmp As String
Dim sFmlRng As String, sFmlRngTmp As String
Dim blAppDisplayAlerts As Boolean
    blAppDisplayAlerts = Application.DisplayAlerts

    Rem Set Ranges & Values
    bVal = 5
    Set rFmlAry = ActiveSheet.Range("D2:D5")

    Rem Define External Reference Variable
    sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

    Rem Define FormulaArray (Original) - with References as Variables
    sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
        "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
        "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

    Rem Set Range to Enter FormulaArray
    Set rFmlAry = ActiveSheet.Range("D7:D10")

    Rem Add Temporary Worksheet
    Application.DisplayAlerts = False
    Set WshTmp = WshTmp_Add(rFmlAry, sFmlRngTmp)

    Rem Set Temporary FormulaArray - Replace long references
    sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)

    Rem Enter Temporary FormulaArray
    rFmlAry.FormulaArray = sFmlAryTmp

    Rem Set FormulaArray (Original) - Replace short references in situ
    rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
        LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
        SearchFormat:=False, ReplaceFormat:=False

    Rem Delete Temporary Worksheet
    WshTmp.Delete
    Application.DisplayAlerts = blAppDisplayAlerts

' ****************************************************************
' Lines for TESTING - Resulting FormulaArray - REMOVED when final
' ****************************************************************
    Rem Validate FormulaArray
    Debug.Print String(3, vbLf)
    Debug.Print "FormulaArray in Range: "
    Debug.Print rFmlAry.Cells(1).FormulaArray
    Debug.Print "FormulaArray VBA: "
    Debug.Print sFmlAry
    If rFmlAry.Cells(1).FormulaArray = sFmlAry Then
        MsgBox "FormulaArray with +255 entered successfully" & vbLf & _
            vbLf & rFmlAry.Cells(1).FormulaArray
    Else
        MsgBox "Something did not worked!" & vbLf & _
            vbLf & "Review formulas printed in the Immediate Window"
            SendKeys "^g": Stop
    End If
' ****************************************************************

End Sub

Как войти FormulaArray более 255 символов, использующих VBA

Похоже, что в этом случае была альтернативная стандартная формула, которая соответствовала требованиям оригинала FormulaArray, Однако могут быть случаи, для которых нет альтернативной формулы. Для этих случаев у меня есть следующий метод ввода FormulaArray с более чем 255 символов, использующих VBA.

Большую часть времени, когда FormulaArray длиннее 255 символов из-за длины references он содержит, как они могут относиться к длинным постоянным массивам, внешние рабочие книги с большими именами (как в этом случае) или рабочие таблицы с большими именами (также в этом случае). Метод заключается в замене этих длинных строк на более короткие, однако для FormulaArray (после замены) быть принятым как FormulaArray эти короткие строки должны также представлять действительные references,

Согласно вышеизложенному, может быть, по крайней мере, три ситуации с references:

  1. Длинные постоянные массивы: в этих случаях используйте Defined Names как описано здесь

https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7

  1. Workbooks с большими именами и
  2. Worksheets с большими именами

Для случаев 2 и 3 применяется тот же метод: использование коротких references указывая на временный Worksheet как временная замена.

Применение метода к этому случаю:

оригинал FormulaArray: использовать переменную sFmlArray держать формулу

Dim sFmlArray As String
sFmlArray = "=INDEX('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!AK:AK," & _
    "MATCH(1,('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$A:$A = A" & bVal & ") * " & _
    "('[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!$B:$B=""Total""),0)) * 1000"

Я предлагаю использовать переменные для хранения имен рабочей книги и рабочего листа, чтобы избежать необходимости записывать их несколько раз.

Dim sFmlRng as string
sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

Замените названия рабочей книги и листа в FormulaArray с соответствующей переменной:

sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
    "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
    "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

Предполагая, что мы хотим войти так долго FormulaArray В диапазоне D7:D10 давайте присвоим его переменной

Dim rFmlAry as Range
Set rFmlAry = ActiveSheet.Range("D7:D10")

Используйте функцию ниже, чтобы добавить временную таблицу. Эта функция также обеспечивает временный reference использоваться в качестве замены в FormulaArray

Function WshTmp_Add(rFmlAry As Range, sFmlRngTmp As String) As Worksheet
    sFmlRngTmp = "@Tmp"
    With rFmlAry.Worksheet.Parent
        On Error Resume Next
        .Worksheets(sFmlRngTmp).Delete
        On Error GoTo 0
        Set WshTmp_Add = .Worksheets.Add(Before:=.Worksheets(1))
    End With
    WshTmp_Add.Name = sFmlRngTmp
    WshTmp_Add.Tab.Color = 255
    sFmlRngTmp = "'" & sFmlRngTmp & "'!"
    Application.Goto rFmlAry
End Function

Заменить в FormulaArray Длинные ссылки с коротким и введите временный FormulaArray в rFmlAry спектр

sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)
rFmlAry.FormulaArray = sFmlAryTmp

С FormulaArray на месте, заменить временную короткую references с оригинальными длинными

rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
    LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
    SearchFormat:=False, ReplaceFormat:=False

Окончательно удали временный Worksheet

Это вся процедура (в качестве теста добавлено несколько строк в конце для проверки результата)

Sub FormulaArray_Over255Chr()
Dim rFmlAry As Range, sFmlAry As String, bVal As Byte

Dim WshTmp As Worksheet, sFmlAryTmp As String
Dim sFmlRng As String, sFmlRngTmp As String
Dim blAppDisplayAlerts As Boolean
    blAppDisplayAlerts = Application.DisplayAlerts

    Rem Set Ranges & Values
    bVal = 5
    Set rFmlAry = ActiveSheet.Range("D2:D5")

    Rem Define External Reference Variable
    sFmlRng = "'[08 Debt Comparison & Provision Report.xlsx]Details by Bus Area &  Location'!"

    Rem Define FormulaArray (Original) - with References as Variables
    sFmlAry = "=INDEX(" & sFmlRng & "AK:AK," & _
        "MATCH(1,(" & sFmlRng & "$A:$A = A" & bVal & ") * " & _
        "(" & sFmlRng & "$B:$B=""Total""),0)) * 1000"

    Rem Set Range to Enter FormulaArray
    Set rFmlAry = ActiveSheet.Range("D7:D10")

    Rem Add Temporary Worksheet
    Application.DisplayAlerts = False
    Set WshTmp = WshTmp_Add(rFmlAry, sFmlRngTmp)

    Rem Set Temporary FormulaArray - Replace long references
    sFmlAryTmp = WorksheetFunction.Substitute(sFmlAry, sFmlRng, sFmlRngTmp)

    Rem Enter Temporary FormulaArray
    rFmlAry.FormulaArray = sFmlAryTmp

    Rem Set FormulaArray (Original) - Replace short references in situ
    rFmlAry.Replace What:=sFmlRngTmp, Replacement:=sFmlRng, _
        LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False, _
        SearchFormat:=False, ReplaceFormat:=False

    Rem Delete Temporary Worksheet
    WshTmp.Delete
    Application.DisplayAlerts = blAppDisplayAlerts

' ****************************************************************
' Lines for TESTING - Resulting FormulaArray - REMOVED when final
' ****************************************************************
    Rem Validate FormulaArray
    Debug.Print String(3, vbLf)
    Debug.Print "FormulaArray in Range: "
    Debug.Print rFmlAry.Cells(1).FormulaArray
    Debug.Print "FormulaArray VBA: "
    Debug.Print sFmlAry
    If rFmlAry.Cells(1).FormulaArray = sFmlAry Then
        MsgBox "FormulaArray with +255 entered successfully" & vbLf & _
            vbLf & rFmlAry.Cells(1).FormulaArray
    Else
        MsgBox "Something did not worked!" & vbLf & _
            vbLf & "Review formulas printed in the Immediate Window"
            SendKeys "^g": Stop
    End If
' ****************************************************************

End Sub

Proidoha

645 / 473 / 38

Регистрация: 04.11.2013

Сообщений: 1,949

1

13.02.2017, 17:07. Показов 4160. Ответов 7

Метки cells, excel, formulaarray, vba (Все метки)


Студворк — интернет-сервис помощи студентам

Доброго времени.

На нескольких листах есть формулы массива, в них макросом надо заменить куски «э140» на «э141»

Пробую так:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
Dim SKV as String
SKV = "э141"
Dim FA As String
For Each iSheet In ThisWorkbook.Worksheets 'на всех листах
    For Each cel In iSheet.UsedRange.Cells 'для каждой ячейки
      If cel.FormulaArray Like "*э140*" Then 'если формула массива содержит "э140"
      FA = Replace(cel.Formula, "э140", SKV) 'собираем строку, заменяя "э140" на "э141"
      cel.FormulaArray = FA 'пытаемся записать нашу фомулу в качестве формулы массива в ячейку.
      End If
    Next cel
Next

cel.FormulaArray = FA не работает. Пишет «нельзя установить свойство FormulaArray класса Range».

Я понимаю, что ему не нравится мой метод выбора ячейки. Как сделать правильно?



0



bedvit

1024 / 227 / 21

Регистрация: 20.05.2016

Сообщений: 971

Записей в блоге: 19

13.02.2017, 17:47

2

Лучший ответ Сообщение было отмечено Proidoha как решение

Решение

Обычным найти и заменить, через рекордер.

Visual Basic
1
Cells.Replace What:="э140", Replacement:="э141", LookAt:=xlPart

Добавлено через 15 минут
На всех листах:

Visual Basic
1
2
3
For Each S In ThisWorkbook.Sheets
S.Cells.Replace What:="э140", Replacement:="э141", LookAt:=xlPart
Next



1



6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

13.02.2017, 17:59

3

Цитата
Сообщение от Proidoha
Посмотреть сообщение

Я понимаю, что ему не нравится мой метод выбора ячейки

— а моему нравится



0



bedvit

1024 / 227 / 21

Регистрация: 20.05.2016

Сообщений: 971

Записей в блоге: 19

13.02.2017, 18:15

4

Замена только для формул содержащих текст:

Visual Basic
1
2
3
4
5
6
Sub Replace_Formul_txt()
Dim S
For Each S In ThisWorkbook.Sheets
S.Cells.SpecialCells(xlCellTypeFormulas, 2).Replace What:="э140", Replacement:="э141", LookAt:=xlPart
Next
End Sub

Добавлено через 2 минуты
Proidoha, у меня ваш код работает, но меняет строку везде, в формулах массива, в обычных, в тексте. Причем обычные формулы содержащие это значения переводит в «массивные». У вас какая задача стоит, где должны быть изменения текста?



1



Proidoha

645 / 473 / 38

Регистрация: 04.11.2013

Сообщений: 1,949

13.02.2017, 18:30

 [ТС]

5

bedvit, спасибо, первый вариант (замена через рекордер, сообщение №2) гораздо быстрее и работает отлично. Взял его.

В том варианте, который я написал, все формулы действительно перегонялись в формулы массива. Эту проблему я решил, но код по прежнему (у меня) не работает (Офис 2016 про, лицензия). Последний МОЙ вариант приложу, вдруг пригодится кому. Проблема решена.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Dim cel As Range
For Each iSheet In ThisWorkbook.Worksheets
    For Each cel In iSheet.UsedRange.Cells
      If cel.Formula Like "*э140*" Then
        If cel.HasArray = False Then 'вот тут добавил проверку на формулу массива
          cel.Formula = Replace(cel.Formula, "э140", SKV) ' все обычные значения и обычные формулы заменяются
        Else
          cel.FormulaArray = Replace(cel.FormulaArray, "э140", SKV) 'на формуле массива по-прежнему затык.
        End If
      End If
    Next cel
Next

П.С. Почитал про эту ошибку. Возникает в разных случаях, однозначного решения нет.



0



bedvit

1024 / 227 / 21

Регистрация: 20.05.2016

Сообщений: 971

Записей в блоге: 19

13.02.2017, 19:43

6

Proidoha, Ваш последний пример работает, но меняет текст везде, в любых данных.

Добавлено через 40 минут
Если вы хотите, что бы текст менялся ТОЛЬКО в формулах массива, то:

Visual Basic
1
2
3
4
5
For Each iSheet In ThisWorkbook.Worksheets
    For Each cel In iSheet.UsedRange.Cells
      If cel.HasArray Then cel.Replace What:="э140", Replacement:="э141", LookAt:=xlPart
    Next cel
Next



1



pashulka

4131 / 2235 / 940

Регистрация: 01.12.2010

Сообщений: 4,624

13.02.2017, 22:06

7

Proidoha, Т.к. формула массива может быть введена в несколько ячеек, то имеет смысл учесть этот факт. А также тот, что в случае отсутствия формул в рабочем листе, использование SpecialCells(xlFormulas) приведёт к ошибке.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Private Sub Test()
 
Application.ScreenUpdating = False
Application.Calculation = xlManual
 
Const SKV = "э141": Dim ws As Worksheet, cell As Range
 
For Each ws In ThisWorkbook.Worksheets
    For Each cell In ws.UsedRange.SpecialCells(xlFormulas)
        If cell.Formula Like "*э140*" Then
           If Not cell.HasArray Then
              cell.Formula = Replace(cell.Formula, "э140", SKV)
           Else
              cell.CurrentArray.FormulaArray = Replace(cell.Formula, "э140", SKV)
           End If
      End If
    Next
Next
 
Application.Calculation = xlAutomatic
Application.ScreenUpdating = True
 
End Sub



0



645 / 473 / 38

Регистрация: 04.11.2013

Сообщений: 1,949

14.02.2017, 09:22

 [ТС]

8

Вариантов предостаточно, всем спасибо. Безотказно работает только cel.Replace What:=»э140″, Replacement:=»э141″, LookAt:=xlPart . Ну, и перед этим различные проверки (на наличие формулы, на наличие массива и т.п. — в зависимости от задачи).
Я использовал вариант из поста #2 — он идеально подошел под мои задачи. Очень шустро заменил и формулы массива, и обычные формулы, и просто надписи (проблема была только с формулами массива, остальное и так менялось). Вариант из поста #6 идеально работает, если надо поменять только формулы массива.



0



Понравилась статья? Поделить с друзьями:
  • Vba excel не работают кнопки
  • Vba excel начало работы
  • Vba excel начало месяца
  • Vba excel находим последний столбец
  • Vba excel натуральный логарифм