2012-04-15 6 views
7

Esiste un modo intelligente utilizzando VBA o una formula per trovare le variabili "k" e "m" in un kx+m string?Excel: trova k e m nella stringa di testo "kx + m"

Ci sono diversi scenari per come il + m stringa kx può guardare, ad es .:

312*x+12 
12+x*2 
-4-x 

e così via. Sono abbastanza sicuro di poterlo risolvere scrivendo formule molto complicate in Excel, ma penso che forse qualcuno abbia già risolto questo e problemi simili. Qui è il mio colpo migliore finora, ma non ha ancora gestire tutte le situazioni (come quando ci sono due svantaggi nella stringa 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));"")))

+2

+! per una domanda interessante :) –

risposta

4

Sono sicuro che questo ti aiuterà :)

Metti questa funzione in un modulo:

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 

Quindi è possibile chiamarlo da una macro ad es. così:

Sub Test() 
    Debug.Print FindKXPlusM("x*312+12") 
End Sub 

Oppure usarlo come una formula. ad es. mettendo questo in una cella:

=FindKXPlusM(B1) 

Mi piace il secondo modo (meno lavoro: P)

ho provato con diversi valori ed ecco una schermata di ciò ottengo:

Screenshot of Find KX+M Formula

Spero che questo aiuti :)

+2

+1 Bello. Mi piace il modo in cui si sta gestendo se è al contrario :) –

+1

regexp è il modo migliore per analizzare la stringa, ma l'analisi è laboriosa per questa applicazione. – brettdj

3

userei un'espressione regolare per cercare una o più cifre dopo "* x" per m e dopo "+" per k

L'esempio mostra valori interi Cosa succede se la pendenza e l'intercetta sono numeri in virgola mobile? I valori firmati? È più complicato del tuo esempio

Suggerirei che la soluzione più generale sarebbe scrivere un lexer/parser con un semplice gra mmar per gestirlo per te. Non so cosa offrono VB o .NET per te. ANTLR avrebbe una soluzione in Java-land; c'è un ANTLR.NET.

Non sono sicuro di quanto tutto questo sforzo ti compri. Cosa farai con i contenuti estratti? Penserei che sarebbe altrettanto facile per gli utenti compilare celle di tipo numerico per k e m e calcolare y = m*x + k da quelle invece di inserire una stringa ed estrarle.

Se il vostro obiettivo è semplicemente quello di valutare una stringa, forse eval() è la vostra risposta:

How to turn a string formula into a "real" formula

+0

+1 Sono d'accordo con te :) È più complesso di quanto sembri. Un 'kx + m' può avere Max 7 operatori e minimo 1 Operatore se non sbaglio. E in uno scenario del genere diventa davvero complesso ottenere i valori "K" e "M". –

4

Si è più complessa di quanto sembri. Un kx + m può avere Max 7 operatori e minimo 1 Operatore se non sbaglio. E in uno scenario del genere diventa davvero complesso ottenere i valori "K" e "M". - Siddharth Rout 33 min fa

Basandosi sul mio commento nel post di duffymo

Questa istantanea mostra le diverse combinazioni che “kx + m” possono avere

enter image description here

E come suggerito in precedenza, è molto complesso ottenere quello che vuoi. Ecco il mio tentativo debole per estrarre solo "K" al momento. Questo codice non è in alcun modo di classe :(Anche io non ho testato il codice con diversi scenari in modo che possa fallire con gli altri.Tuttavia ti dà una buona idea su come affrontare questo problema. aggiustalo di più per ottenere i risultati esatti che vuoi.

CODICE (Sto testando per 7 combinazioni possibili in questo codice.Funziona per questi 7 ma potrebbe/fallirà per gli altri)

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 

ISTANTANEA

enter image description here

Non è molto, ma spero che questo si ottiene in strada giusta ...

+0

+1 ben considerato – brettdj

+0

+1 bello senza Regexp –

5

Piuttosto che perdere tempo con analisi eseguire una semplice LINEST in VBA.

Sostituire StrFunc come necessario

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 
+1

+1 Molto creativo! – Excellll

Problemi correlati