字符串到标记序列

时间:2011-08-24 15:16:35

标签: c# string tokenize

我正在解析命令序列字符串,需要将每个字符串转换为字符串[],它将按照读取的顺序包含命令令牌。

原因在于这些序列存储在数据库中以指示协议客户端为各个远程应用程序执行某个规定的序列。这些字符串中有特殊的标记,我需要自己添加到字符串[]中,因为它们不代表传输的数据;相反,它们表示阻塞暂停。

序列不包含分隔符。在命令序列中的任何地方都可以找到任意数量的特殊标记,这就是为什么我不能简单地用正则表达式解析字符串的原因。此外,序列中的所有这些特殊命令都包含${}

以下是我需要解析为令牌的数据示例(P1表示阻止暂停一秒钟):

"some data to transmit${P1}more data here"

结果数组应如下所示:

{ "some data to transmit", "${P1}", "more data here" }

我认为LINQ可以帮助解决这个问题,但我不太确定。我能想到的唯一解决方案是循环遍历每个字符,直到找到$,然后检测是否有特殊的暂停命令,然后使用索引从那里解析序列。

3 个答案:

答案 0 :(得分:2)

一个选项是使用Regex.Split(str, @"(\${.*?})")并忽略当你有两个特殊标记彼此相邻时得到的空字符串。

也许Regex.Split(str, @"(\${.*?})").Where(s => s != "")就是你想要的。

答案 1 :(得分:1)

好的,正如评论中提到的那样,我建议你阅读lexers。他们有能力做你所描述的一切和更多。

由于您的要求如此简单,我会说手动编写词法分析器并不困难。这是一些可以做到的伪代码。

IEnumerable<string> tokenize(string str) {

    var result = new List<string>();
    int pos = -1;
    int state = 0;
    int temp = -1;

    while( ++pos < str.Length ) {
        switch(state) {
            case 0:
                if( str[pos] == "$" ) { state = 1; temp = pos; }
                break;
            case 1:
                if( str[pos] == "{" ) { state = 2; } else { state = 0; }
                break;
            case 2:
                if( str[pos] == "}" } {
                    state = 0;
                    result.Add( str.Substring(0, temp) );
                    result.Add( str.Substring(temp, pos) );
                    str = str.Substring(pos);
                    pos = -1;
                }
                break;
            }
    }

    if( str != "" ) {
        result.Add(str);
    }

    return result;
}

或类似的东西。我通常在第一次尝试时得到Substring的参数错误,但这是一般的想法。

使用ANTLR之类的东西,你可以获得更强大(更容易阅读)的词法分析器。

答案 2 :(得分:0)

使用Gabe的一点建议,我想出了一个完全符合我要求的解决方案:

string tokenPattern = @"(\${\w{1,4}})";
string cmdSequence = "${P}test${P}${P}test${P}${Cr}";

string[] tokenized = (from token in Regex.Split(cmdSequence, tokenPattern)
                      where token != string.Empty
                      select token).ToArray();

使用上例中的命令序列,数组包含:

{ "${P}", "test", "${P}", "${P}", "test", "${P}", "${Cr}"}