2016-02-29 2 views
1

ситуации

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

Информация всегда состоит из двух столбцов. Верх первого столбца будет содержать формулу, сохраненную в виде строки. Нижняя часть первого столбца будет содержать UDF. Между формулой и UDF будут все переменные из формулы строки. Второй столбец будет содержать все числовые значения для переменных.

Проблема

Я не знаю, как выбрать верхнюю часть колонны информации или переменных выше ОДС в автоматическом методе, так как я не знаю, как определить местоположение ячейки ОДС помещается в.

Objective

Ссылка расположение ячейки ОДС находится в так, что расположение формулы ячейки и диапазона для переменной клеток может быть определена. Я пытаюсь написать UDF таким образом, что мне не нужно передавать ему адрес ячейки формулы или переменных. Я хочу, чтобы он сам захватил эту информацию, основываясь на всей информации, непосредственно примыкающей к ячейке с UDF без пробелов.

То, что я

Option Explicit 

Public Function SolvedEquation() As Long 

Dim FormulaCell As Range 
Dim Equation As String 
Dim VariableRange As Range 
Dim VariableCell As Range 
Dim VariablesLength As Integer 
Dim Variable As String 
Dim VariableValue As Double 

'define FormulaCell as the last nonblank up from the cell the function is called in from a contiguous range(no spaces) 
FormulaCell = Application.ThisCell.End(xlUp).Select 

'define the VariableRange as one up from the cell the function is called to second last cell non blank cell located upward in a contiguous selection (no spaces) 
VariableRange = Range(Cells(Application.ThisCell.Row - 1, Application.ThisCell.Column), Cells(FormulaCell.Row + 1, FormulaCell.Column)) 

Equation = FormulaCell.Value 

For Each VariableCell In VariableRange.Cells 

    VariablesLength = Len(VariableCell.Value)-1 
    Variable = Left(VariableCell.Value, VariablesLength) 
    VariableValue = Cells(VariableCell.Row, VariableCell.Column + 1).Value 
    Equation = Replace(FormulaCell.Value, Variable, VariableValue) 

Next VariableCell 

SolvedEquation = Evaluate(Equation) 

End Function 

Предложения для лучшего кодирования оценены (т.е. выбор диапазона по ячейкам)

Пример данных

enter image description here

С некоторыми исправлениями кода от лиц ниже я закончил с этим до сих пор. Там, где появляется 177,00 в ячейке, должно быть указано 176.86. КОРРЕКЦИЯ: эта последняя проблема исправлена ​​путем переопределения типа переменной, как это сделал Крис в своих отзывах.

+2

Я в замешательстве - вы пишете «Я не знаю, как определить местоположение ячейки, в которую помещается UDF», но затем вы даете код, который использует «Application.ThisCell», который именно так вы определяете расположение ячейки, в которую помещается UDF ". В чем ваш вопрос? –

+0

Ну, изначально у меня был «выбор». Я провел некоторое исследование, и я нашел кого-то, использующего «Приложение .ThisCell», поэтому я попробовал это, но мой код не работает, и если я правильно помню его сбой при первом использовании application.thiscell. Поэтому я не думал, что это правильно закодировано. –

+0

'Application.Caller' также работает. Кроме того, вы не можете использовать 'Select' в UDF –

ответ

1

Есть целый ряд вопросов, в вашем коде, не связанные непосредственно с ThisCell

См инлайны комментариями

Public Function SolvedEquation() As Variant '~~> allow for Error result 
    Dim FormulaCell As Range 
    Dim Equation As String 
    Dim VariableRange As Range 
    Dim VariableCell As Range 
    Dim VariablesLength As Integer 
    Dim Variable As String 
    Dim VariableValue As Double 

    'define FormulaCell as the last nonblank up from the cell the function is called in from a contiguous range(no spaces) 
    '~~> You must use Set and not use .Select 
    '~~> but this wont give you what you want if the cell above ThisCell is blank 
    'Set FormulaCell = Application.ThisCell.End(xlUp) 
    '~~> use this instead 
    If Application.ThisCell.Row <= 2 Then 
     ' Function is in row 1 or 2. What now? 
     SolvedEquation = CVErr(xlErrNA) 
     Exit Function 
    Else 
     If IsEmpty(Application.ThisCell.Offset(-1, 0)) Then 
      Set FormulaCell = Application.ThisCell 
     Else 
      Set FormulaCell = Application.ThisCell.End(xlUp) 
     End If 
    End If 

    'define the VariableRange as one up from the cell the function is called to second last cell non blank cell located upward in a contiguous selection (no spaces) 
    '~~> use Set 
    '~~> define worksheet 
    '~~> simplify 
    'VariableRange = Range(Cells(Application.ThisCell.Row - 1, Application.ThisCell.Column), Cells(FormulaCell.Row + 1, FormulaCell.Column)) 
    With Application.ThisCell 
     Set VariableRange = Range(.Offset(-1, 0), FormulaCell.Offset(1, 0)) 
    End With 
    Equation = FormulaCell.Value 

    For Each VariableCell In VariableRange.Cells 
     VariablesLength = Len(VariableCell.Value) '- 1 
     Variable = Left$(VariableCell.Value, VariablesLength) '~~> string version of Left is faster 
     VariableValue = VariableCell.Offset(0, 1).Value '~~> simplify 
     Equation = Replace$(Equation, Variable, VariableValue) '~~> string version of Replace is faster, continue to work on Equation 
    Next VariableCell 

    SolvedEquation = Evaluate(Equation) 

End Function 

Тем не менее, ваш метод имеет неотъемлемую проблему, что он не будет автоматически пересчитывать, когда его изменения входных данных, поскольку в вызове функции нет ссылки на исходные данные. Лучший способ передать Range параметр в UDF ссылающегося уравнение и исходные данные, как этот

Public Function SolvedEquation2(rng As Range) As Variant 
    Dim dat As Variant 
    Dim Equation As Variant 
    Dim i As Long 

    ' copy range data to an array 
    dat = rng.Value 

    ' Verify size of range 
    If UBound(dat, 1) < 2 Or UBound(dat, 2) < 2 Then 
     SolvedEquation2 = CVErr(xlErrNA) 
     Exit Function 
    End If 

    ' Solve equation 
    Equation = dat(1, 1) 
    For i = 2 To UBound(dat, 1) 
     Equation = Replace$(Equation, dat(i, 1), dat(i, 2)) 
    Next 
    ' Use Worksheet version of Evaluate 
    SolvedEquation2 = rng.Worksheet.Evaluate(Equation) 
End Function 

Примечание: Я не понимаю, почему вам нужно манипулировать переменные, как вы, так что я вышло. Если это является необходимо обновление ваш Q с некоторыми образцами данных и ожидаемых Equation строки, и я буду обновлять А

Основываясь на образец, формула будет SolvedEquation2(O129:P133)

Примечание: Его лучше использовать версию рабочего листа оценки.See this link from Charles Williams' website for reason why

+0

Усовершенствование - 'SolvedEquation2 = rng.Parent.Evaluate (Equation)' или 'Evaluate' будет использовать контекст любого листа, который будет активным в то время, что может привести к неправильному вывод. –

+0

Крис сделал несколько хороших указателей на базовое кодирование. Я всегда пропускаю «набор», поскольку я никогда не уверен, когда это необходимо. если память правильно работает, когда вы имеете дело с адресом или диапазоном ячейки. Крис также подчеркивает, что если я когда-либо изменил, изменил одно из значений переменных или сама формула, он не обновил бы и не пересчитал бы сам. Если это так, то это очень проблематично. Я пытался добиться размещения этого UDF на нескольких листах и ​​нескольких местах на листе без необходимости добавлять диапазон информации, на основе которой рассчитывается каждый раз. –

+0

@Chris Я не знал, что смещение может быть использовано таким образом или что осталось $/replace $. Спасибо за образование по этому поводу. –

Смежные вопросы