我想编写一个像命令外壳一样工作的应用程序(询问命令,执行它,然后询问下一个命令,重复)。但是,当我尝试将书面命令分成几个单独的部分时,我立即失败了。
我不仅要在空格处分割命令,而且还希望允许参数包含空格,只要将它们放在双引号之间即可。
即使我逐行检查代码,也无法弄清楚代码出了什么问题。
Module Module1
Dim _exit As Boolean = False
Dim prompt As String = ""
Dim Title As String = ""
Sub Main()
Console.Title = Title
While Not _exit
Console.Write(prompt)
Dim returned As String = Console.ReadLine
Dim parts() As String = split_with_string(returned, False)
If parts(0) = "exit" Then
_exit = True
ElseIf parts(0) = "" Then
'Space for Commands
Else
Console.WriteLine("Unknown Command")
End If
End While
End Sub
Private Function secindex(ByVal str As String, character As Char)
Return str.IndexOf(character, str.IndexOf(character) + 1)
End Function
Private Function split_with_string(ByVal str As String, ByVal return_parts As Boolean)
Dim returned As String = str
Dim parts As New List(Of String)
_next:
If returned.Length = 1 Then
parts.Add(returned)
ElseIf returned.StartsWith("""") Then
parts.Add(returned.Substring(1, secindex(returned, """") - 1))
returned = returned.Substring(secindex(returned, """") + 1)
ElseIf returned.StartsWith(" ") Then
returned = returned.Substring(1)
Else
If returned.Contains(" ") Then
parts.Add(returned.Substring(0, returned.IndexOf(" ")))
returned = returned.Substring(returned.IndexOf(" ") + 1)
Else
parts.Add(returned)
returned = ""
End If
End If
If Not returned.Length < 1 Then
GoTo _next
End If
If return_parts Then
For Each xx In parts.ToArray
Console.WriteLine(xx)
Next
End If
Return parts.ToArray
End Function
End Module
如果布尔值设置为true,我希望函数将结果写入控制台。
答案 0 :(得分:3)
Regex使复杂的字符串解析变得如此容易。它具有自己的陡峭的学习曲线,但是由于它是许多语言和编程工具中都可以使用的标准工具,所以您迟早要熟悉它。
例如,如果您要获取如下所示的列表:
one
two
"this is three"
"this is four"
five
您可以使用如下代码:
Public Sub Main()
Dim parts() As String = ParseCommand("one two ""this is three"" ""this is four"" five")
For Each part As String In parts
Console.WriteLine(part)
Next
End Sub
Private Function ParseCommand(input As String) As String()
Return Regex.Matches(input, "(?!"")\S+|""[^""]+""").
Cast(Of Match)().
Select(Function(m) m.Value).
ToArray()
End Function
但是,如果您希望它去除引号,那么输出如下所示:
one
two
this is three
this is four
five
您可以对正则表达式模式进行一些调整,例如:
Private Function ParseCommand(input As String) As String()
Return Regex.Matches(input, "(?<p>(?!"")\S+)|""(?<p>[^""]+)""").
Cast(Of Match)().
Select(Function(m) m.Groups("p").Value).
ToArray()
End Function
如果您对正则表达式不熟悉,它会使用一种模式在输入字符串中寻找匹配的子字符串。在第一个示例中,它要寻找的模式是(?!")\S+|"[^"]+"
。因此,它将在输入字符串中查找与该模式匹配的所有部分,并仅返回那些匹配的子字符串。模式的含义如下:
(?!")\S+
-与任何以"
开头的单词匹配
(?!")
-(?! ... )
子句中包含的所有内容均称为否定预见。这意味着紧随其后的是该子句中列出的所有内容。在这种情况下,这意味着接下来出现的所有内容都不能以"
字符开头。\S
-这表示任何非空格字符,因此任何非空格或制表符之类的东西+
-这意味着必须有一个或多个这些非空格字符|
-这是布尔值OR,表示它可以匹配之前或之后的所有内容"[^"]+"
-这匹配两个"
字符之间的所有单词,包括任何空格
"
-说匹配项必须以"
开头[^"]
-[^ ... ]
子句中包含的所有内容均为负字符类。这意味着它可以是不是该子句中列出的字符之一的任何字符。在这种情况下,就是说任何不是"
的字符。+
-这意味着必须有一个或多个这些非引号字符"
-说匹配的内容必须以"
第二种模式基本上是同一回事,但是它稍微先进一点,因为它使用命名组(例如(?<name> sub-pattern)
)来匹配整个匹配的某些部分。