Excel: найти k и m в текстовой строке " kx + m
есть ли умный способ использования VBA
или формула для поиска переменных" k "и" m " в A kx+m string
?
существует несколько сценариев того, как строка kx+m может выглядеть, например:
312*x+12
12+x*2
-4-x
и так далее. Я уверен, что могу решить эту проблему, написав очень сложные формулы в Excel, но я думаю, что, возможно, кто-то уже решил эту и подобные проблемы. Вот мой лучший снимок до сих пор, но он еще не обрабатывает все ситуации (например ,когда есть два минуса в строка kx+m:
=TRIM(IF(NOT(ISERROR(SEARCH("~+";F5)));
IF(SEARCH("~+";F5)>SEARCH("~*";F5);RIGHT(F5;LEN(F5)-SEARCH("~+";F5));LEFT(F5;SEARCH("~+";F5)-1));
IF(NOT(ISERROR(SEARCH("~-";F5)));
IF(SEARCH("~-";F5)>SEARCH("~*";F5);RIGHT(F5;LEN(F5)-SEARCH("~-";F5)+1);LEFT(F5;SEARCH("~*";F5)-1));"")))
4 ответов
Я уверен, что это поможет вам :)
поместите эту функцию в модуль:
Function FindKXPlusM(ByVal str As String) As String
Dim K As String, M As String
Dim regex As Object, matches As Object, sm As Object
'' remove unwanted spaces from input string (if any)
str = Replace(str, " ", "")
'' create an instance of RegEx object.
'' I'm using late binding here, but you can use early binding too.
Set regex = CreateObject("VBScript.RegExp")
regex.IgnoreCase = True
regex.Global = True
'' test for kx+m or xk+m types
regex.Pattern = "^(-?\d*)\*?x([\+-]?\d+)?$|^x\*(-?\d+)([\+-]?\d+)?$"
Set matches = regex.Execute(str)
If matches.Count >= 1 Then
Set sm = matches(0).SubMatches
K = sm(0)
M = sm(1)
If K = "" Then K = sm(2)
If M = "" Then M = sm(3)
If K = "-" Or K = "+" Or K = "" Then K = K & "1"
If M = "" Then M = "0"
Else
'' test for m+kx or m+xk types
regex.Pattern = "^(-?\d+)[\+-]x\*([\+-]?\d+)$|^(-?\d+)([\+-]\d*)\*?x$"
Set matches = regex.Execute(str)
If matches.Count >= 1 Then
Set sm = matches(0).SubMatches
M = sm(0)
K = sm(1)
If M = "" Then M = sm(2)
If K = "" Then K = sm(3)
If K = "-" Or K = "+" Or K = "" Then K = K & "1"
If M = "" Then M = "0"
End If
End If
K = Replace(K, "+", "")
M = Replace(M, "+", "")
'' the values found are in K & M.
'' I output here in this format only for showing sample.
FindKXPlusM = " K = " & K & " M = " & M
End Function
тогда вы можете либо вызвать его из макроса например, вот так:
Sub Test()
Debug.Print FindKXPlusM("x*312+12")
End Sub
или используйте его как формулу. например, поместив это в ячейку:
=FindKXPlusM(B1)
мне нравится второй способ (меньше работы :P)
Я тестировал его с различными значениями и вот скриншот того, что получилось у меня:
надеюсь, что это помогает :)
вместо того, чтобы беспокоиться о разборе запустить простой LINEST
в VBA.
заменить StrFunc
по мере необходимости
Sub Extract()
Dim strFunc As String
Dim X(1 To 2) As Variant
Dim Y(1 To 2) As Variant
Dim C As Variant
X(1) = 0
X(2) = 100
strFunc = "312*x+12"
'strFunc = "12+x*2 "
'strFunc = "-4-X"
Y(1) = Evaluate(Replace(LCase$(strFunc), "x", X(1)))
Y(2) = Evaluate(Replace(LCase$(strFunc), "x", X(2)))
C = Application.WorksheetFunction.LinEst(Y, X)
MsgBox "K is " & C(1) & vbNewLine & "M is " & C(2)
End Sub
это сложнее, чем кажется. Kx+m может иметь максимум 7 операторов и минимум 1 оператора, если я не ошибаюсь. И в таком сценарии становится очень сложно получить значения" K "и" M". - Сиддхарт Раут 33 минуты назад
основываясь на моем комментарии в сообщении duffymo
этот снимок показывает различные комбинации, которые "kx + m" может иметь
и как предложенный ранее, очень сложно достичь того, что вы хотите. Вот мой слабая попытка извлечь "K" на данный момент. этот код никоим образом не классный : (также я не тестировал код с различными сценариями, поэтому он может завершиться неудачей с другими. Однако это дает вам четкое представление о том, как подойти к этой проблеме. Вам придется настроить его больше, чтобы получить точные результаты, которые вы хотеть.
код (я тестирую 7 возможных комбинаций в этом коде. Он работает для этих 7, но может / не удастся для других)
Option Explicit
Sub Sample()
Dim StrCheck As String
Dim posStar As Long, posBrk As Long, pos As Long, i As Long
Dim strK As String, strM As String
Dim MyArray(6) As String
MyArray(0) = "-k*(-x)+(-m)*(-2)"
MyArray(1) = "-k*x+(-m)*(-2)"
MyArray(2) = "-k(x)+(-m)*(-2)"
MyArray(3) = "-k(x)+(-m)(-2)"
MyArray(4) = "-kx+m"
MyArray(5) = "kx+m"
MyArray(6) = "k(x)+m"
For i = 0 To 6
StrCheck = MyArray(i)
Select Case Left(Trim(StrCheck), 1)
Case "+", "-"
posBrk = InStr(2, StrCheck, "(")
posStar = InStr(2, StrCheck, "*")
If posBrk > posStar Then '<~~ "-k*(-x)+(-m)*(-2)"
pos = InStr(2, StrCheck, "*")
If pos <> 0 Then
strK = Mid(StrCheck, 1, pos - 1)
Else
strK = Mid(StrCheck, 1, posBrk - 1)
End If
ElseIf posBrk < posStar Then '<~~ "-k(-x)+(-m)*(-2)"
pos = InStr(2, StrCheck, "(")
strK = Mid(StrCheck, 1, pos - 1)
Else '<~~ "-kx+m"
'~~> In such a case I am assuming that you will never use
'~~> a >=2 letter variable
strK = Mid(StrCheck, 1, 2)
End If
Case Else
posBrk = InStr(1, StrCheck, "(")
posStar = InStr(1, StrCheck, "*")
If posBrk > posStar Then '<~~ "k*(-x)+(-m)*(-2)"
pos = InStr(1, StrCheck, "*")
If pos <> 0 Then
strK = Mid(StrCheck, 1, pos - 2)
Else
strK = Mid(StrCheck, 1, posBrk - 1)
End If
ElseIf posBrk < posStar Then '<~~ "k(-x)+(-m)*(-2)"
pos = InStr(1, StrCheck, "(")
strK = Mid(StrCheck, 1, pos - 2)
Else '<~~ "kx+m"
'~~> In such a case I am assuming that you will never use
'~~> a >=2 letter variable
strK = Mid(StrCheck, 1, 1)
End If
End Select
Debug.Print "Found " & strK & " in " & MyArray(i)
Next i
End Sub
снимок
это не так много, но я надеюсь, что это приведет вас на правильный путь...
Я бы использовал регулярное выражение для поиска одной или нескольких цифр; после "*x "для m и после" + " для k.
в вашем примере показаны целочисленные значения. Что, если наклон и перехват-это числа с плавающей точкой? Подписанные значения? Это сложнее, чем может показаться на вашем примере.
Я бы предположил, что наиболее общим решением было бы написать лексер/парсер с простой грамматикой, чтобы справиться с этим для вас. Я не знаю, что VB или .NET предлагают для вас. ANTLR бы один решение в Java-land; существует ANTLR.NET.
Я не уверен, что все эти усилия покупает вас. Что вы будете делать с извлеченным содержимым? Я бы подумал, что пользователям будет так же легко заполнять ячейки числового типа для k и m и вычислять y = m*x + k
из них, а не вставлять строку и извлекать их.
Если ваша цель-просто оценить строку, может быть,eval()
ваш ответ: