Здравствуйте В Excel при активной формуле в ячейке выделенную часть ссылки можно изменить в постоянный массив клавишей F9. Например, в файле формула =ВПР(D8;$L$8:$M$12;2;) при выделении $L$8:$M$12 и использовании F9 преобразится в =ВПР(D8;{"a";1:"b";2:"c";3:0;0:0;0};2;) . Как макросом в выделенных столбцах(в файле E:G) во всех формулах изменить все ссылки в постоянный массив? В ячейке E5 формула уже преобразована.
Оговорки 1. если будет выделен столбец, то будет засада. 2. Если в диапазоне много значений и итоговая длинна массива большая то нужно придумывать еще и это обрабатывать при замене. 3. если будет не только ссылка, но и похожий текст, то будет замена ложная 4. закрепления областей - я сделал в примере только перебор 4х вариантов, а их 8 и еще не учитывается ссылка на другой лист, хотя это можно доработать. На другую книгу (что сложнее ведь она может быть закрытой). 5. Я только концепт предложил, это не финишное решение.
Скрытый текст
Код
Sub test()
Dim wRange As Range, oRange As Range, Cell As Range, oArea As Range
Dim S As String
On Error Resume Next
Set wRange = Selection.SpecialCells(xlCellTypeFormulas)
If Err = 0 Then
on error goto 0
For Each Cell In wRange
For Each oArea In Cell.DirectPrecedents.Areas
If oArea.Count > 1 Then
D = oArea
ReDim d1(1 To UBound(D, 2)), d2(1 To UBound(D, 1))
For i = 1 To UBound(D, 1)
For j = 1 To UBound(D, 2)
d1(j) = IIf(IsEmpty(D(i, j)), 0, D(i, j))
If Not IsNumeric(d1(j)) Then d1(j) = """" & d1(j) & """"
Next
d2(i) = Join(d1, ",")
Next
S = "{" & Join(d2, ";") & "}"
For i = 0 To 1
For j = 0 To 1
' Debug.Print oArea.Address(-i, -j)
' cell.Formula = Replace(cell.Formula, oArea.Address(-i, -j, s)
' cell.Replace What:=oArea.Address(-i, -j) , Replacement:=s, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
wRange.Replace What:=oArea.Address(-i, -j), Replacement:=S, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
Next
Next
End If
Next
Next
End If
End Sub
Только сей час заметил что есть решение в теме. Макрос да, отработал на примере. Большое спасибо! Однако не знаю почему не работает на других формулах. В файл добавил формулы в те же ячейки как и в рабочем файле. Диапазоны выделены, но выделять буду по одному диапазону.
Думаю достигнут предел длины текстового изменения. На первой формуле подстановка в 321 символ. Я выше чуть подправил. особенно обработка ошибки мешалась.
все, накрылась идея. если диапазоны в разных частях перекрываются или слипаются, то получим результирующий объединенный диапазон. что будет не корректным. а примере =IF($N$21>=95;IFERROR(HLOOKUP(N6;$E$117:$H$133;MATCH($C6;$D$117:$D$133;));)*L6;0) получаем $D$117:$H$133 - что естесвенно не корректно
Концепт 2 но по прежнему большой массив не вставит.
Скрытый текст
Код
Sub test1()
Dim wRange As Range, oRange As Range, Cell As Range, oArea As Range
Dim Seps As Variant, Sep As Variant
Seps = Array("=", ",", "+", "-", "/", "*", "&", "(", ")", "<", ">")
Dim F As String, S As String, args As Variant, arg As Variant
On Error Resume Next
Set wRange = Intersect(Selection, Cells.SpecialCells(xlCellTypeFormulas))
If Err = 0 Then
On Error GoTo 0
For Each Cell In wRange
F = Cell.Formula
For Each Sep In Seps
F = Replace(F, Sep, Chr(1))
Next
args = Split(F, Chr(1))
For Each arg In args
If InStr(arg, ":") > 0 Then
arg = Trim(arg)
On Error Resume Next
Set oArea = Range(arg)
If Err = 0 Then
On Error GoTo 0
If oArea.Count > 1 Then
Set Check = Intersect(Cell.DirectPrecedents, Range(arg))
If Not Check Is Nothing Then
If Check.Count = Range(arg).Count Then
D = oArea
ReDim d1(1 To UBound(D, 2)), d2(1 To UBound(D, 1))
For i = 1 To UBound(D, 1)
For j = 1 To UBound(D, 2)
d1(j) = IIf(IsEmpty(D(i, j)), 0, D(i, j))
If Not IsError(d1(j)) Then
If Not IsNumeric(d1(j)) Then d1(j) = """" & d1(j) & """"
End If
Next
d2(i) = Join(d1, ",")
Next
S = "{" & Join(d2, ";") & "}"
' Debug.Print oArea.Address(-i, -j)
Cell.Formula = Replace(Cell.Formula, arg, S)
' cell.Replace What:=oArea.Address(-i, -j) , Replacement:=s, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
'wRange.Replace What:=arg, Replacement:=S, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
End If
End If
End If
End If
End If
Next
Next
End If
End Sub
да, там определением переменных намудрил, Это не проблема. А вот
Цитата
Михаил Л написал: Жестко прописать ссылку на диапазон.
не помогает ибо как оказалось найти это не так сложно, хоть и не в две строки, а заменить через замену не получается. Только если в каждой ячейке править, что дольше.
приветствую! Я не в теме задачи, но ведь всегда можно взять массив arr = Range().Formula, поработать с формулами, как со строками и выгрузить обратно Range().Formula = arr
Михаил Л, здравствуйте Скажите, пожалуйста, если не секрет, в чём глобальный смысл данных действий? Зачем может быть нужно заменять ссылки на их значения? Кстати, ссылка по теме замены ссылок на значения (есть ещё версия в надстройке Multex)).
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: о ведь всегда можно взять массив arr = Range().Formula
это не изменит принципиально ничего, также перебор всех формул, и сделает только сложнее проверку на то, действительно ли взят диапазон, а не похожий текст. Также придется дробить на поддиапазоны в случае есливыделено несколько диапазонов. В чем смысл замены - это во всех формулах чехом заменить диапазон , если он повторяется.
БМВ: сделает только сложнее проверку на то, действительно ли взят диапазон, а не похожий текст.
вообще тебя не понял. Формулы начинаются со знака "=" — вот тебе и вся проверка.
Цитата
БМВ: Также придется дробить на поддиапазоны в случае есливыделено несколько диапазонов.
это называется области: Range.Areas. И тут тоже ничего сложного. Сложность в том, как написать парсер для строки формулы, а не как его применить для Selection.Areas.Count.
Цитата
БМВ: В чем смысл замены - это во всех формулах чехом заменить диапазон , если он повторяется.
хоспади, ну не нужно ли ТЕБЕ объяснять, что "чехом" — это такой же цикл, только скрытый от твоих глаз. Встраиваешь в парсер статичный словарь и сохраняешь отобранные замены.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Михаил Л написал: В файл добавил формулы в те же ячейки как и в рабочем файле
Цитата
Jack Famous написал: в чём глобальный смысл данных действий? Зачем может быть нужно заменять ссылки на их значения?
Все просто, зашить массив в формулу, а диапазоны данных удалить с листа. Вообще там целая история с этими премиями. Первый раз сделал в PQ и PP, но мою работу проверяет финдиректор. Он вызвал меня и мне пришлось объяснять что такое срезы и почему при нажатии кнопки среза меняются данные, почему в файле только один лист, где все данные, как работает впр, не шарлатан ли я. В итоге сказали сделать как у нормальных людей и мне пришлось для каждого сотрудника(40+ листов) делать отдельный лист и копипастить данные.
Цитата
Михаил Л написал: В файл добавил формулы в те же ячейки как и в рабочем файле
Формулы будут только эти, достаточно в макросе жестко прописать ссылку на диапазон. Может сделать макрос для одной ссылки($T$90:$W$129 изменить в массив)? А я бы уже накопировал бы макросов под каждую ссылку.
ничего , но уже цикл по ним и отдельная обработка каждого что приведет клибо к невозможности найденный диапазон заменить сразу везде.
Цитата
Jack Famous написал: что "чехом" — это такой же цикл, только скрытый от твоих глаз
да да, ты попробуй тоже продлеать с Массивной формулой.
короче, прежде чем свое непонимание высказывать, ты б разобраться попытался, в мелочах.
Цитата
Михаил Л написал: Может сделать макрос для одной ссылки($T$90:$W$129 изменить в массив)?
это сильно упрощает задачу, но вы должны понимать, что подобное изменение ведет к росту объема файла, и тяжко для контроля. строку подстановки из заранее определенного диапазона сформировать не сложно
это вот эта часть
Код
D = oArea
ReDim d1(1 To UBound(D, 2)), d2(1 To UBound(D, 1))
For i = 1 To UBound(D, 1)
For j = 1 To UBound(D, 2)
d1(j) = IIf(IsEmpty(D(i, j)), 0, D(i, j))
If Not IsError(d1(j)) Then
If Not IsNumeric(d1(j)) Then d1(j) = """" & d1(j) & """"
End If
Next
d2(i) = Join(d1, ",")
Next
S = "{" & Join(d2, ";") & "}"
А пробежаться и заменить шило на мыло по всем ячейкам в выделенной области с формулами и заменить -ваще просто.
Цитата
Михаил Л написал: Первый раз сделал в PQ и PP, но мою работу проверяет финдиректор. Он вызвал меня и мне пришлось объяснять что такое срезы и почему при нажатии кнопки среза меняются данные, почему в файле только один лист, где все данные, как работает впр, не шарлатан ли я.
- интересно, он в магазин наверно до сих пор с наличкой ходит.
БМВ написал: подобное изменение ведет к росту объема файла
Увеличение на объем текста макроса? У меня макросы в отдельной книге. Или увеличение на объем массива в каждой формуле? Пусть увеличивается, там 110 формул, не будет критично.
чтоб его показать, его надо написать ;-) . Может вечером, но не обещаю.
Однако вопрос в приложении файл, который получен после работы макроса, который ниже.
Скрытый текст
Код
Sub test1()
Dim wRange As Range, oRange As Range, Cell As Range, oArea As Range
Dim Seps As Variant, Sep As Variant
Seps = Array("=", ",", "+", "-", "/", "*", "&", "(", ")", "<", ">")
Dim F As String, S As String, args As Variant, arg As Variant
On Error Resume Next
Set wRange = Intersect(Selection, Cells.SpecialCells(xlCellTypeFormulas))
If Err = 0 Then
On Error GoTo 0
For Each Cell In wRange
F = Cell.Formula
For Each Sep In Seps
F = Replace(F, Sep, Chr(1))
Next
args = Split(F, Chr(1))
For Each arg In args
If InStr(arg, ":") > 0 Then
arg = Trim(arg)
On Error Resume Next
Set oArea = Range(arg)
If Err = 0 Then
On Error GoTo 0
If oArea.Count > 1 Then
Set Check = Intersect(Cell.DirectPrecedents, Range(arg))
If Not Check Is Nothing Then
If Check.Count = Range(arg).Count Then
D = oArea
ReDim d1(1 To UBound(D, 2)), d2(1 To UBound(D, 1))
For i = 1 To UBound(D, 1)
For j = 1 To UBound(D, 2)
d1(j) = IIf(IsEmpty(D(i, j)), 0, D(i, j))
If Not IsError(d1(j)) Then
If Not IsNumeric(d1(j)) Then d1(j) = """" & d1(j) & """"
End If
Next
d2(i) = Join(d1, ",")
Next
S = "{" & Join(d2, ";") & "}"
' Debug.Print oArea.Address(-i, -j)
Cell.Formula = Replace(Cell.Formula, arg, S)
' cell.Replace What:=oArea.Address(-i, -j) , Replacement:=s, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
'wRange.Replace What:=arg, Replacement:=S, LookAt:=xlPart, SearchFormat:=False, ReplaceFormat:=False
End If
End If
End If
End If
End If
Next
Next
End If
End Sub
То что можно переделать - можно. только нужно понимать оно того стоит или текущего достаточно, и если стоит , то более точно сформулировать что нужно.
Этом макрос уже рабочий! В файле в выделенном диапазоне P6:S20 он отработает до первой ошибки. Однако если в диапазоне T90:W129 убрать формулы, вызывающие ошибку(деление на ноль), то макрос отработает как надо. Большое спасибо! Все отлично!
На дробных числах потребовалось добавить замену запятой на точку
Код
For j = 1 To UBound(D, 2)
d1(j) = IIf(IsEmpty(D(i, j)), 0, D(i, j))
If Not IsError(d1(j)) Then
If Not IsNumeric(d1(j)) Then
d1(j) = """" & d1(j) & """"
Else: d1(j) = Replace(d1(j), ",", ".")
End If
Else: d1(j) = """+++"""
End If
Next