Probabiz Пользователь Сообщений: 3 |
Здравствуйте! Прикрепленные файлы
|
БМВ Модератор Сообщений: 21378 Excel 2013, 2016 |
Probabiz, Не совсем понятен вопрос. Действительно вставить макросом формулу длиннее 255 не получится в случае если это массивная. Существует 4 метода Ну и 5. сократить саму формулу — было 154 Изменено: БМВ — 11.01.2020 14:46:03 По вопросам из тем форума, личку не читаю. |
skais675 Пользователь Сообщений: 2177 |
А где же лист КоммунСервис? Изменено: skais675 — 11.01.2020 14:16:21 |
Probabiz Пользователь Сообщений: 3 |
#4 11.01.2020 14:24:22 Это я не доподчистил файл, пропустил. Лист переименован на «заявка» БМВ, а как симмулируется CTRL+SHIFT+ENTER?
Это с помощью операторов DIm и Replace правильно понимаю? |
||
БМВ Модератор Сообщений: 21378 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 |
#6 11.01.2020 16:23:06
БМВ, спасибо за подсказки и напутствия! Все формулы укоротил, как Вы и говорили с помощью диспетчера имен. И ошибка Нельзя установить свойство Formulaarray для класса Range пропала. Все заполняется как надо. |
||
skais675 Пользователь Сообщений: 2177 |
Probabiz Исходя из вышесказанного, нужно было все макросом сделать используя массивы — а это совсем другая тема. |
БМВ Модератор Сообщений: 21378 Excel 2013, 2016 |
#8 11.01.2020 17:01:59
это было из-за использования целых столбцов. Убежден, что сейчас будет в десятки раз быстрее, даже если в именах заменить 10000 на 60000 или даже 10000.
— да тема другая, но как обычно сперва фундамент надежный, а потом дом, а тут фундамент подкачал, каков бы технологичный дом небыл — рухнет, что собственно и происходило. Прикрепленные файлы
Изменено: БМВ — 11.01.2020 17:06:50 По вопросам из тем форума, личку не читаю. |
||||
Кирилл Журенко Пользователь Сообщений: 4 |
#9 30.01.2021 19:47:08 Добрый день! Дабы не плодить темы, решил спросить здесь. Ошибка та же, что и у ТС. Но у меня проблема не в длинной формуле, а в чем-то другом, никак не могу понять.
А вот такая уже нет:
SSRange — диапазон в виде строки типа «A3:A6». Если вводить в ячейку эту формулу вручную, не через VBA, то все работает. Изменено: 0rtega — 30.01.2021 20:34:32 |
||||
sokol92 Пользователь Сообщений: 4445 |
#10 30.01.2021 20:47:26
Сомневаюсь. Свойство FormulaArray не локализовано, должны быть «американские» имена функций и разделители. Владимир |
||
БМВ Модератор Сообщений: 21378 Excel 2013, 2016 |
#11 30.01.2021 20:50:37
и это не правильно По вопросам из тем форума, личку не читаю. |
||
0rtega Пользователь Сообщений: 4 |
#12 30.01.2021 21:18:13
Напрасно, можете проверить и убедиться сами. За подсказку про локализацию спасибо, исправил, однако результат тот же. На строке:
выдается та же ошибка.
Первый раз такое на форумах встречаю. На всякий случай уточню: мне следует создать аналогичную тему с тем же вопросом, что и у ТС, и описать свою ситуацию? И ее не удалят в связи с пунктом 3.7 Правил? Изменено: 0rtega — 30.01.2021 21:19:37 |
||||||
БМВ Модератор Сообщений: 21378 Excel 2013, 2016 |
#13 30.01.2021 21:35:55 просто у вас вопрос синтаксиса, а именно , разделитель ; должен быть в VBA ,
а можно
или
По вопросам из тем форума, личку не читаю. |
||||||
0rtega Пользователь Сообщений: 4 |
#14 30.01.2021 22:02:34
Заработало! Спасибо большое! Получается, это справедливо только для FormulaArray? До этого в обычных формулах (FormulaLocal) в VBA всегда использовал точку с запятой, никогда проблем не возникало… Изменено: 0rtega — 30.01.2021 22:07:17 |
||
Вы не обращали внимания на то, что тут ключевое — Local. Т.е. формула должна вводиться в той локализации, которая применена в Excel и формула будет работать. А в FormulaArray у Вас где Local? Нигде. А значит надо вводить на «интернациональном» для VBA языке и по его правилам. А этот английский с разделителем аргументов запятая. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
|
0rtega Пользователь Сообщений: 4 |
Дмитрий(The_Prist) Щербаков, спасибо большое за разъяснение |
Дмитрий(The_Prist) Щербаков Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
#17 31.01.2021 10:29:35
и снова не так. См. выше мой ответ: разделители применяются те, которые установлены в ОС в качестве разделителя функций(списков). Т.е. в точности так же, как Вы их вводите с листа без VBA. А это могут быть и запятые, если локализация изначально английская. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||
Как ввести формулу массива, длиной >256 знаков через VBA |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
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
:
- 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
Workbooks
with large names andWorksheets
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
:
- Длинные постоянные массивы: в этих случаях используйте
Defined Names
как описано здесь
https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
Workbooks
с большими именами и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» Пробую так:
cel.FormulaArray = FA не работает. Пишет «нельзя установить свойство FormulaArray класса Range». Я понимаю, что ему не нравится мой метод выбора ячейки. Как сделать правильно?
0 |
bedvit 1024 / 227 / 21 Регистрация: 20.05.2016 Сообщений: 971 Записей в блоге: 19 |
||||||||
13.02.2017, 17:47 |
2 |
|||||||
Сообщение было отмечено Proidoha как решение РешениеОбычным найти и заменить, через рекордер.
Добавлено через 15 минут
1 |
6875 / 2807 / 533 Регистрация: 19.10.2012 Сообщений: 8,562 |
|
13.02.2017, 17:59 |
3 |
Я понимаю, что ему не нравится мой метод выбора ячейки — а моему нравится
0 |
bedvit 1024 / 227 / 21 Регистрация: 20.05.2016 Сообщений: 971 Записей в блоге: 19 |
||||
13.02.2017, 18:15 |
4 |
|||
Замена только для формул содержащих текст:
Добавлено через 2 минуты
1 |
Proidoha 645 / 473 / 38 Регистрация: 04.11.2013 Сообщений: 1,949 |
||||
13.02.2017, 18:30 [ТС] |
5 |
|||
bedvit, спасибо, первый вариант (замена через рекордер, сообщение №2) гораздо быстрее и работает отлично. Взял его. В том варианте, который я написал, все формулы действительно перегонялись в формулы массива. Эту проблему я решил, но код по прежнему (у меня) не работает (Офис 2016 про, лицензия). Последний МОЙ вариант приложу, вдруг пригодится кому. Проблема решена.
П.С. Почитал про эту ошибку. Возникает в разных случаях, однозначного решения нет.
0 |
bedvit 1024 / 227 / 21 Регистрация: 20.05.2016 Сообщений: 971 Записей в блоге: 19 |
||||
13.02.2017, 19:43 |
6 |
|||
Proidoha, Ваш последний пример работает, но меняет текст везде, в любых данных. Добавлено через 40 минут
1 |
pashulka 4131 / 2235 / 940 Регистрация: 01.12.2010 Сообщений: 4,624 |
||||
13.02.2017, 22:06 |
7 |
|||
Proidoha, Т.к. формула массива может быть введена в несколько ячеек, то имеет смысл учесть этот факт. А также тот, что в случае отсутствия формул в рабочем листе, использование SpecialCells(xlFormulas) приведёт к ошибке.
0 |
645 / 473 / 38 Регистрация: 04.11.2013 Сообщений: 1,949 |
|
14.02.2017, 09:22 [ТС] |
8 |
Вариантов предостаточно, всем спасибо. Безотказно работает только cel.Replace What:=»э140″, Replacement:=»э141″, LookAt:=xlPart . Ну, и перед этим различные проверки (на наличие формулы, на наличие массива и т.п. — в зависимости от задачи).
0 |