我在使用Visual C#创建一个非常基本的结构分析软件的第一步。
我决定让它基于控制台(没有用户界面)。因此,获取用户输入的唯一方法是通过字符和字符串。
想象一下,用户想要创建一个2D条形元素。她需要指定该条的初始点,最终点和名称。我希望语法如下:
“CREATE bar NAMED(bar_name)FIRST(first_point)LAST(last_point)”
其中:
我只是想知道是否有任何简单的方法来实现字符串比较任务,比如将用户的输入与预制命令进行比较。
当然不会忘记用户的输入清洁任务。
我知道这里有很多可能的解决方案。也许使用LINQ。也许只是使用String对象。我只想知道最有效的方法,其中有效的方法是:
最后一点非常重要,因为有些用户输入如下:
“CREATE bar NAMED bar_a FISRT (0,0)LAST(0,1)”
请注意,用户提交了拼写错误(FISRT而不是FIRST),查询不应该运行。
由于
答案 0 :(得分:1)
标记化是一种方法,但如果你不打算支持太多的命令和参数,你应该看看Regexes。
Regex regex = new Regex(@"^CREATE bar NAMED (?<BarName>[A-Za-z0-9-_]*) FIRST (?<FirstPoint>\([0-9]+\|[0-9]+\)) LAST (?<LastPoint>\([0-9]+\|[0-9]+\)$");
Match match = regex.Match("create bar named bar_a first (0,0) last (0,1)", RegexOptions.IgnoreCase);
if (match.Success)
{
var name = match.Groups["BarName"].Value;
// and so on for other matches
}
答案 1 :(得分:1)
好的,我创建了一个适合您的简单解析器,如果需要,您可以轻松扩展。
首先创建一个新的控制台应用程序。添加名为Tokenizer.cs
的新类文件。这个文件是由我在上面的评论中链接到你的TokenIcer项目自动生成的。让Tokenizer.cs
看起来像这样:
public class TokenParser
{
private readonly Dictionary<Tokens, string> _tokens;
private readonly Dictionary<Tokens, MatchCollection> _regExMatchCollection;
private string _inputString;
private int _index;
public enum Tokens
{
UNDEFINED = 0,
CREATE = 1,
FIRST = 2,
LAST = 3,
BAR = 4,
NAMED = 5,
BAR_NAME = 6,
WHITESPACE = 7,
LPAREN = 8,
RPAREN = 9,
COMMA = 10,
NUMBER = 11
}
public string InputString
{
set
{
_inputString = value;
PrepareRegex();
}
}
public TokenParser()
{
_tokens = new Dictionary<Tokens, string>();
_regExMatchCollection = new Dictionary<Tokens, MatchCollection>();
_index = 0;
_inputString = string.Empty;
_tokens.Add(Tokens.CREATE, "[Cc][Rr][Ee][Aa][Tt][Ee]");
_tokens.Add(Tokens.FIRST, "[Ff][Ii][Rr][Ss][Tt]");
_tokens.Add(Tokens.LAST, "[Ll][Aa][Ss][Tt]");
_tokens.Add(Tokens.BAR, "[Bb][Aa][Rr][ \\t]");
_tokens.Add(Tokens.NAMED, "[Nn][Aa][Mm][Ee][Dd]");
_tokens.Add(Tokens.BAR_NAME, "[A-Za-z_][a-zA-Z0-9_]*");
_tokens.Add(Tokens.WHITESPACE, "[ \\t]+");
_tokens.Add(Tokens.LPAREN, "\\(");
_tokens.Add(Tokens.RPAREN, "\\)");
_tokens.Add(Tokens.COMMA, "\\,");
_tokens.Add(Tokens.NUMBER, "[0-9]+");
}
private void PrepareRegex()
{
_regExMatchCollection.Clear();
foreach (KeyValuePair<Tokens, string> pair in _tokens)
{
_regExMatchCollection.Add(pair.Key, Regex.Matches(_inputString, pair.Value));
}
}
public void ResetParser()
{
_index = 0;
_inputString = string.Empty;
_regExMatchCollection.Clear();
}
public Token GetToken()
{
if (_index >= _inputString.Length)
return null;
foreach (KeyValuePair<Tokens, MatchCollection> pair in _regExMatchCollection)
{
foreach (Match match in pair.Value)
{
if (match.Index == _index)
{
_index += match.Length;
return new Token(pair.Key, match.Value);
}
if (match.Index > _index)
{
break;
}
}
}
_index++;
return new Token(Tokens.UNDEFINED, string.Empty);
}
public PeekToken Peek()
{
return Peek(new PeekToken(_index, new Token(Tokens.UNDEFINED, string.Empty)));
}
public PeekToken Peek(PeekToken peekToken)
{
int oldIndex = _index;
_index = peekToken.TokenIndex;
if (_index >= _inputString.Length)
{
_index = oldIndex;
return null;
}
foreach (KeyValuePair<Tokens, string> pair in _tokens)
{
var r = new Regex(pair.Value);
Match m = r.Match(_inputString, _index);
if (m.Success && m.Index == _index)
{
_index += m.Length;
var pt = new PeekToken(_index, new Token(pair.Key, m.Value));
_index = oldIndex;
return pt;
}
}
var pt2 = new PeekToken(_index + 1, new Token(Tokens.UNDEFINED, string.Empty));
_index = oldIndex;
return pt2;
}
}
public class PeekToken
{
public int TokenIndex { get; set; }
public Token TokenPeek { get; set; }
public PeekToken(int index, Token value)
{
TokenIndex = index;
TokenPeek = value;
}
}
public class Token
{
public TokenParser.Tokens TokenName { get; set; }
public string TokenValue { get; set; }
public Token(TokenParser.Tokens name, string value)
{
TokenName = name;
TokenValue = value;
}
}
在Program.cs
中,请将其显示如下:
class Program
{
private class Bar
{
public string Name { get; set; }
public int FirstX { get; set; }
public int FirstY { get; set; }
public int LastX { get; set; }
public int LastY { get; set; }
}
static void Main(string[] args)
{
const string commandCreateBar1 = "CREATE bar NAMED bar_a FIRST(5,10) LAST (15,20)";
const string commandCreateBar2 = "CREATE bar NAMED MyFooBar FIRST(25 , 31) LAST (153 ,210)";
const string commandCreateBar3 = "CREATE bar NAMED MySpaceyFooBar FIRST(0,0) LAST (12,39)";
Bar bar1 = ParseCreateBar(commandCreateBar1);
PrintBar(bar1);
Bar bar2 = ParseCreateBar(commandCreateBar2);
PrintBar(bar2);
Bar bar3 = ParseCreateBar(commandCreateBar3);
PrintBar(bar3);
}
private static void PrintBar(Bar bar)
{
Console.WriteLine("A new bar was Created! \"{0}\" ({1}, {2}) ({3}, {4})", bar.Name, bar.FirstX, bar.FirstY, bar.LastX, bar.LastY);
}
private static Bar ParseCreateBar(string commandLine)
{
var bar = new Bar();
var parser = new TokenParser { InputString = commandLine };
Expect(parser, TokenParser.Tokens.CREATE);
Expect(parser, TokenParser.Tokens.BAR);
Expect(parser, TokenParser.Tokens.NAMED);
Token token = Expect(parser, TokenParser.Tokens.BAR_NAME);
bar.Name = token.TokenValue;
Expect(parser, TokenParser.Tokens.FIRST);
Expect(parser, TokenParser.Tokens.LPAREN);
token = Expect(parser, TokenParser.Tokens.NUMBER);
bar.FirstX = int.Parse(token.TokenValue);
Expect(parser, TokenParser.Tokens.COMMA);
token = Expect(parser, TokenParser.Tokens.NUMBER);
bar.FirstY = int.Parse(token.TokenValue);
Expect(parser, TokenParser.Tokens.RPAREN);
Expect(parser, TokenParser.Tokens.LAST);
Expect(parser, TokenParser.Tokens.LPAREN);
token = Expect(parser, TokenParser.Tokens.NUMBER);
bar.LastX = int.Parse(token.TokenValue);
Expect(parser, TokenParser.Tokens.COMMA);
token = Expect(parser, TokenParser.Tokens.NUMBER);
bar.LastY = int.Parse(token.TokenValue);
Expect(parser, TokenParser.Tokens.RPAREN);
return bar;
}
private static Token Expect(TokenParser parser, TokenParser.Tokens expectedToken)
{
EatWhiteSpace(parser);
Token token = parser.GetToken();
if (token != null && token.TokenName != expectedToken)
{
Console.WriteLine("Expected Token " + expectedToken);
Environment.Exit(0);
}
if (token == null)
{
Console.WriteLine("Unexpected end of input!");
Environment.Exit(0);
}
return token;
}
private static void EatWhiteSpace(TokenParser parser)
{
while (parser.Peek() != null && parser.Peek().TokenPeek != null &&
parser.Peek().TokenPeek.TokenName == TokenParser.Tokens.WHITESPACE)
{
parser.GetToken();
}
}
}
如您所见,我创建了3个测试场景。请注意,忽略所有空格。如果您想严格控制空格,可以将EatWhiteSpace
函数修改为严格。
如果你愿意,我有一个简单的表达式解析器,我也可以投入到这个代码中,这样你就可以拥有CREATE bar NAMED bar_a FIRST(3+2, 7*8 + 12) LAST (150-100, 12-3*2)
之类的命令。我有一个简单的表达式解析器我使用TokenIcer做了一段时间我可以投入。它可以解析任何数学表达式并支持括号,加,减,乘和除。