c# - 解释和格式化用户输入
问题描述
我正在为我的软件设计一个命令行解释器,并且需要能够格式化用户输入。目前我有一个基本上用空格分割所有内容的系统,问题是我不需要在双引号内分割任何内容。
正如您可能知道的那样,我当前的实现不能很好地处理引用路径。
这是我当前的解释和格式化逻辑(包含在一个非静态方法中,当用户按下回车键时会调用该方法,以防有人想知道):
var command = ConsoleInput.Text;
ConsoleInput.Text = String.Empty;
string command_main = command.Split(new char[] { ' ' }).First();
string[] synatx = command.Split(new char[] { ' ' }).Skip(1).ToArray();
if (lCommands.ContainsKey(command_main))
{
Action<string[]> commandfunction;
lCommands.TryGetValue(command_main, out commandfunction);
commandfunction(synatx);
}
else
ConsoleOut($"Invalid Command - {command_main} {string.Join(" ", synatx)}");
我需要引用路径作为单个参数,而不是按间距分割。例如,(免责声明:这只是一个示例,而不是实际代码)
这是我不想要 的:输入:“这是一个测试”和更多文本,结果是这样的:syntax[0] = "this syntax[1] = is,依此类推.
预期的结果将是(我想要发生的): syntax[0] = "this is a test" syntax[1] = 和 syntax[2] = some,依此类推。
我卡在这里,有人有解决方案吗?谢谢你。
解决方案
这是一个解决方案。它是一个组合在一起的状态机,可以处理可能包含空格的引用字符串。它丢弃参数之间无关的空格,并将双引号视为单个双引号(但没有任何特殊含义;就好像它是任何其他字符)。
public IEnumerable<string> ParseLine(string toParse)
{
var result = new List<string>();
bool inQuotedString = false;
bool parsingDoubleQuote = false;
bool inWhiteSpace = false;
int length = toParse.Length;
var argBuffer = new StringBuilder();
for (var index = 0; index < length; ++index)
{
//if looking ahead for a double quote succeeded, just add the quote to the current arguemnt
if (parsingDoubleQuote)
{
parsingDoubleQuote = false;
argBuffer.Append('"');
//and we are done with this character, so...
continue; //done with this character, time to just loop again
}
if (toParse[index] == '"')
{
inWhiteSpace = false;
//look ahead one character to see if there's a double quote
if (index < length - 1 && toParse[index + 1] == '"')
{
parsingDoubleQuote = true;
continue; //done with this character, time to just loop again
}
if (!inQuotedString)
{
inQuotedString = true;
continue; //done with this character, time to just loop again
}
else
{
//it's not a double quote, and we are in quotes string, so
inQuotedString = false;
//we don't add the buffer to the output args until a space or the end, so
continue; //done with this character, time to just loop again
}
}
//if we are here, there's no quote, so...
if (toParse[index] == ' ' || toParse[index] == '\t')
{
if (inQuotedString)
{
argBuffer.Append(toParse[index]);
continue; //done with this character, time to just loop again
}
if (inWhiteSpace)
{
//nothing to do
continue; //out of the for loop
}
else
{
inWhiteSpace = true;
if (argBuffer.Length > 0)
{
result.Add(argBuffer.ToString());
argBuffer.Clear();
continue; //done with this character, time to just loop again
}
}
}
else
{
inWhiteSpace = false;
//no quote, no space, so...
argBuffer.Append(toParse[index]);
continue; //done with this character, time to just loop again
}
} //end of for loop
if (argBuffer.Length > 0)
{
result.Add(argBuffer.ToString());
}
return result;
}
我已经对其进行了粗略的测试——你会想要更努力地测试它
推荐阅读
- ansible - 如何在 Ansible Play 期间修复 Broken pipe 错误
- javascript - 数组解析并转换为具有特定输出的新数组列表
- python - 返回随机值
- arrays - 如何使用 Google 表格中查询功能的 select 语句从单元格中获取文本?
- node.js - 对 Google Cloud NodeJs API 的首次请求比后续请求花费更多时间
- laravel - 模型没有查询结果,Laravel
- php - 您无权访问此资源
- r - 编织完成后上传文件
- javascript - Laravel:使用 npm 包 - ReferenceError
- java - 如何通过网关访问微服务的 Socket