Befehl erkennen

  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Befehl erkennen

    Hi Leute,

    ich hab da mal ne Frage...
    Und da ich keine Antwort finde, Stelle ich sie einfach mal hier ;)

    Ich arbeite an einem Programm, welches eine Fernsteuerung für meinen 2ten PC sein soll.
    Also hab ich mir es ein wenig umständlich gemacht, und mir einen TCP Server umgeschrieben.
    Ich hab also einen Server, ein Senderprogramm, und ein Empfängerprogramm.
    Momentan funktioniert das Programm aber leider nur als einseitiger chat :D

    Meine Frage ist nun:
    Wie sage ich meinem Empfängerprogramm, dass er bei einer Nachricht, die Mit einem / anfängt erstmal guckt, welches wort nach dem / kommt und diese dann in einer MSGBox ausgibt?

    Ich habs schon mit einer Kombination aus If Abfrage und

    VB.NET-Quellcode

    1. Dim 1 As Char = empfangener Text(1)

    versucht, aber das ist ziemlich umständlich da ich dann ja jeden Buchstaben einzelnd überprüfen muss. :D

    Gibt es da irgentwie eine bessere möglichkeit?
    Da gibt's viele Möglichkeiten. Das hängt von dem gesendeten Befehl ab.
    Schreib uns mal ein paar Beispiele, damit wir sehen, wie die Befehle aussehen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich hätte auf anhieb mal 2 beispiele:

    1. "/shutdown" (soll den PC mit "Shell("shutdown -s -t 20")" herunterfahren
    2. wenn möglich "/kill [Prozessname]" (soll den Prozess mit dem Namen [Prozessname] beenden)
    z.B. so:

    VB.NET-Quellcode

    1. Select Case True
    2. Case Befehl.Contains("/kick")
    3. 'führe das kicken aus
    4. Case Befehl.Contains("/close")
    5. 'führe den befehl close aus z.B. me.Close oder sowas
    6. End Select



    wenn du parameter wie bei deinem fall (im nächsten post hab ich übersehen) das mit dem prozessnamen dann z.B. so

    VB.NET-Quellcode

    1. Select Case True
    2. Case Befehl.Contains("/kick")
    3. Dim splitter() as string = befehl.split(" ")
    4. /kill splitter(0) 'wäre in dem fall der erste parameter der durch ein leerzeichen (" ") getrennt wurde.
    5. End Select
    6. [Achtung Pseudocode]

    Hoffe du verstehst es.
    Vielleicht möchtest Du Dir ein etwas handlicheres System zulegen, wenn Du kompliziertere Befehle hast.
    Du könntest eine MustInherit Basisklasse namens Action verwenden, die eine MustOverride Funktion namens "Execute" parat hält.
    Alle abgeleiteten Klassen wissen, ob sie mit dem Befehl gemeint sind und wissen, was bei einem Befehl zu tun ist.
    Dann kannst Du das hier anwenden: [VB 2010] Statische Funktionen abgeleiteter Klassen aufrufen um Dir eine TryParse-Funktion zu schreiben.
    Das wird die Sache auf Dauer vereinfachen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hi
    folgendes wäre wahrscheinlich angemessener:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Shared Sub Test()
    2. Dim commandList As New CommandList(True)
    3. commandList.Add(New Command("msgBox", New Action(Of String)(Sub(p) MessageBox.Show(p)), _
    4. New Action(Of String, String)(Sub(x, y) MessageBox.Show(x + " " + y))))
    5. InvokeCommand("\MsgBox HelloWorld \MsgBox test merge", commandList)
    6. End Sub
    7. Public Shared Sub InvokeCommand(ByVal commandString As String, ByVal commandList As CommandList)
    8. For Each commandInstance As CommandCall In InterpretCommand(commandString, commandList)
    9. commandInstance.Invoke()
    10. Next
    11. End Sub
    12. Public Shared Function InterpretCommand(ByVal commandString As String, ByVal commandList As CommandList) As IEnumerable(Of CommandCall)
    13. 'momentaner String-Index
    14. Dim ind As Integer = 0
    15. 'string-Laenge
    16. Dim count As Integer = commandString.Length
    17. 'Liste der auszufuehrenden Aufrufe
    18. Dim output As ICollection(Of CommandCall) = New LinkedList(Of CommandCall)()
    19. Dim currentCommand As Command = Nothing
    20. Dim args As New List(Of String)(256)
    21. Dim temp As String 'Zwischenspeicher fuer Bezeichner
    22. While ind < count
    23. If Char.IsWhiteSpace(commandString(ind)) Then 'Leerzeichen entfernen
    24. ind += 1
    25. ElseIf commandString(ind) = "\"c Then 'ist der momentane Buchstabe ein "\"c, so ist das nachfolgende Wort ein Bezeichner (auch \\ ist gueltig, usw.)
    26. If currentCommand IsNot Nothing Then 'Bestehenden Aufruf einreihen und Argumenten-Liste leeren
    27. output.Add(New CommandCall(currentCommand, args.ToArray()))
    28. args.Clear()
    29. End If
    30. ind += 1
    31. temp = ReadWord(commandString, ind) 'Kommando-Bezeichner lesen
    32. currentCommand = commandList.Item(temp) 'Kommando ermitteln
    33. If currentCommand Is Nothing Then
    34. Throw New InvalidOperationException("Command """ + temp + """ was not found.")
    35. End If
    36. ElseIf currentCommand IsNot Nothing Then
    37. args.Add(ReadWord(commandString, ind)) 'andere Faelle als Argument einreihen
    38. Else
    39. Throw New ArgumentException("Command expected before arguments.")
    40. End If
    41. End While
    42. If currentCommand IsNot Nothing Then 'letzten Aufruf einreihen
    43. output.Add(New CommandCall(currentCommand, args.ToArray()))
    44. End If
    45. Return output 'Aufrufe zurueckgeben
    46. End Function
    47. Public Shared Function ReadWord(ByVal input As String, ByRef index As Integer) As String
    48. 'ab dem ersten Nicht-Leerzeichen alle Nicht-Leerzeichen lesen
    49. Dim count As Integer = input.Length
    50. While index < count AndAlso Char.IsWhiteSpace(input(index))
    51. index += 1
    52. End While
    53. If index < count Then
    54. Dim startIndex As Integer = index
    55. While index < count AndAlso Not Char.IsWhiteSpace(input(index))
    56. index += 1
    57. End While
    58. Return input.Substring(startIndex, index - startIndex)
    59. Else
    60. Return Nothing
    61. End If
    62. End Function
    63. Public Class CommandCall
    64. Private ReadOnly _command As Command
    65. Private ReadOnly _parameters() As String
    66. Private ReadOnly _overload As System.Reflection.MethodInfo
    67. Public ReadOnly Property Command As Command
    68. Get
    69. Return _command
    70. End Get
    71. End Property
    72. Public ReadOnly Property Parameters() As String()
    73. Get
    74. Return _parameters
    75. End Get
    76. End Property
    77. Public Sub Invoke()
    78. _overload.Invoke(Nothing, _parameters)
    79. End Sub
    80. Public Sub New(ByVal command As Command, ByVal parameters() As String)
    81. _command = command
    82. _parameters = parameters
    83. _overload = command.GetOverload(parameters.Length)
    84. If _overload Is Nothing Then
    85. Throw New ArgumentException("No command found that matches the specified parameter count.")
    86. End If
    87. End Sub
    88. End Class
    89. Public Class Command
    90. Private ReadOnly _overloads As IDictionary(Of Integer, System.Reflection.MethodInfo)
    91. Private ReadOnly _name As String
    92. Public Sub AddOverload(ByVal method As System.Reflection.MethodInfo) 'Ueberladung fuer Kommando hinzufuegen
    93. Dim param() As System.Reflection.ParameterInfo = method.GetParameters()
    94. For i As Integer = 0 To param.Length - 1
    95. If param(i).ParameterType <> GetType(String) Then
    96. 'oder Typ-Konversion zu String ueber TypeConverter oder dergleichen
    97. Throw New ArgumentException("All method parameters have to derive from string.")
    98. End If
    99. Next
    100. _overloads.Add(param.Length, method)
    101. End Sub
    102. Public Sub AddOverload(ByVal methodDelegate As [Delegate])
    103. If methodDelegate.Target Is Nothing Then
    104. AddOverload(methodDelegate.Method)
    105. Else
    106. 'Delegaten mit Ziel-Instanz kann man ja noch unterstuetzen
    107. Throw New ArgumentException("Cannot add targeted delegates.")
    108. End If
    109. End Sub
    110. Public Function GetOverload(ByVal parameterCount As Integer) As System.Reflection.MethodInfo
    111. GetOverload = Nothing
    112. If Not _overloads.TryGetValue(parameterCount, GetOverload) Then
    113. Return Nothing
    114. End If
    115. End Function
    116. Public ReadOnly Property Name As String
    117. Get
    118. Return _name
    119. End Get
    120. End Property
    121. Public Sub New(ByVal name As String)
    122. If String.IsNullOrEmpty(name) OrElse ContainsWhitespaces(name) Then
    123. Throw New ArgumentException("Name mustnot be null, empty or contain any whitespaces.")
    124. End If
    125. _overloads = New Dictionary(Of Integer, System.Reflection.MethodInfo)()
    126. _name = name
    127. End Sub
    128. Public Sub New(ByVal name As String, ByVal ParamArray defaultOverloadMethods() As System.Reflection.MethodInfo)
    129. Me.New(name)
    130. For Each overload As System.Reflection.MethodInfo In defaultOverloadMethods
    131. AddOverload(overload)
    132. Next
    133. End Sub
    134. Public Sub New(ByVal name As String, ByVal ParamArray defaultOverloads() As [Delegate])
    135. Me.New(name)
    136. For Each overload As [Delegate] In defaultOverloads
    137. AddOverload(overload)
    138. Next
    139. End Sub
    140. Private Shared Function ContainsWhitespaces(ByVal value As String) As Boolean
    141. For Each c As Char In value
    142. If Char.IsWhiteSpace(c) Then
    143. Return True
    144. End If
    145. Next
    146. Return False
    147. End Function
    148. End Class
    149. Public Class CommandList
    150. Inherits System.Collections.ObjectModel.KeyedCollection(Of String, Command)
    151. Protected Overrides Function GetKeyForItem(ByVal item As Command) As String
    152. Return item.Name
    153. End Function
    154. Public Sub New()
    155. MyBase.New(StringComparer.InvariantCulture)
    156. End Sub
    157. Public Sub New(ByVal ignoreCase As Boolean)
    158. MyBase.New(If(ignoreCase, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCulture))
    159. End Sub
    160. End Class

    Damit fällt die Vererbung weg und man hat auch sowas, wie einfache Überladungen der Aufrufe. Man könnte auch noch eine einfache Regel einführen, nach der Arrays gesondert behandelt werden oder wenn man es komplex machen will, könnte man die einzelnen Kommandos auch noch ineinander verschachteln, speziellere Ausdrücke einführen usw. Da kann man dann aber auch gleich was anständiges schreiben.

    Übrigens: Contains überprüft, ob eine Zeichenkette eine andere Zeichenkette enthält. Folgende Aussagen sind somit alle gültig:

    VB.NET-Quellcode

    1. Debug.Assert("Hello World".Contains("Hello World"))
    2. Debug.Assert(Not "Hello World".Contains("Hello World!"))
    3. Debug.Assert("Hello World".Contains("llo Wor"))
    4. Debug.Assert("\kick".Contains("\kick"))
    5. Debug.Assert("böses \kick".Contains("\kick"))
    6. Debug.Assert("\kicknochböser".Contains("\kick"))
    7. Debug.Assert(Not "\KiCk".Contains("\kick"))


    Gruß
    ~blaze~

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()