老赵的《趣味编程:从字符串中提取信息》的一个解决方案

足足3个月没有打开我的Visual Studio 2008,超过半年没有认认真真写过C# ,今天突然看到老赵提出了一个问题——趣味编程:从字符串中提取信息 ,勾起了我对大学时光的怀念,特写此文。

老赵的问题简单的来说,就是从以下这段字符串:

cpu-3.0g--color-red-green-black--price-5000-8000--weight-'3-'--keywords-'levi''s'

解析得出需要的信息:

new List
{
    new string[] { "cpu", "3.0g" },
    new string[] { "color", "red", "green", "black" },
    new string[] { "price", "5000", "8000" },
    new string[] { "weight", "3-" },
    new string[] { "keywords", "levi's" },
}

看到这个问题一下子就让我想起了大学的《编译原理》的词法分析器,我十分怀疑老赵是不是在某本编译原理的书里面得到灵感的,呵呵呵呵。

这是我们当时的课本:

bb289e9f-7a4a-40d4-817c-c08c803c731c好难懂,认认真真学一周,竟然看不明白一章书,唉……,现在基本上都忘得差不多了……,下文有什么说得不恰当的地方欢迎大家指正。

我的程序是基于状态机来做的,优点就是对输入仅作一次向前的扫描。

缺点非常明显——难维护,相当难维护,用时髦一点的语言来说叫不够敏捷。

还是言归正传吧,我用的是状态机的思路去解决这个问题。

我将老赵所说的字符归为三类:

1。平常字符,例如:A-Za-z0-9.,+等,简称Common、C

2。分隔符,这里只有一个 - , 简称 Splitor、S

3。块符,这里也只有一个 ' 简称 Block 、 B

其实可以简单地认为,除了第二、第三种剩下的就是第一种了。

构建一个状态跳转图,知识忘记得太多了,可能图不标准。

image 突然,发现远看这个状态跳转图也挺有艺术感的啊,哈哈哈哈。

我用哈希表存储这张图:

//构建跳转表
DictionaryJumpWorkTable=newDictionary();
JumpTable.Add("0,Common",1);
JumpTable.Add("0,Block",4);
JumpTable.Add("0,Splitor",0);
JumpTable.Add("1,Splitor",2);
JumpTable.Add("1,Common",1);
JumpTable.Add("2,Common",1);
JumpTable.Add("2,Splitor",3);
JumpTable.Add("2,Block",4);
JumpTable.Add("3,Common",1);
JumpTable.Add("3,Block",4);
JumpTable.Add("4,Common",4);
JumpTable.Add("4,Splitor",4);
JumpTable.Add("4,Block",5);
JumpTable.Add("5,Block",4);
JumpTable.Add("5,Splitor",2);

每一步跳转都会依据输入进行一定的处理,对应的表如下:

Dictionary JumpWorkTable = new Dictionary();
JumpWorkTable.Add("0,1", start);
JumpWorkTable.Add("0,0", idle);
JumpWorkTable.Add("1,1", inputCommonChar);
JumpWorkTable.Add("1,2", endToken);
JumpWorkTable.Add("2,1", startToken);
JumpWorkTable.Add("2,3", endGroup);
JumpWorkTable.Add("2,4", startToken);
JumpWorkTable.Add("3,1", startToken);
JumpWorkTable.Add("3,4", startToken);
JumpWorkTable.Add("4,4", inputCommonChar);
JumpWorkTable.Add("4,5", idle);
JumpWorkTable.Add("5,4", inputCommonChar);
JumpWorkTable.Add("5,2", endToken);

根据这两张表做的动作就很简单了:

/// 
/// 从一个状态跳转到另一个状态
/// 
/// 现在所处的状态
/// 输入的char
/// 跳转到新的状态
public int Jump(int nowPosition, char c)
{
    if (((int)c) > 0)
    {
        string jump = nowPosition.ToString() + "," + JudgeChar(c);
        int nextPosition = JumpTable[jump];
        string work = nowPosition.ToString() + "," + nextPosition;
        JumpWorkTable[work](c);
        return nextPosition;
    }
    else
    {
        //不重要
    }
}

主程序调用也很简单了:

InputSource source = new InputSource();
FSM fsm = new FSM();
int nowPosition = 0;

while (source.HashToken())
{
    char c = source.GetNextChar();
    nowPosition = fsm.Jump(nowPosition, c);
}
fsm.Jump(nowPosition, (char)0);

可以说,整个程序的核心就是要弄明白上面的状态跳转图,以及每步跳转要做什么事情。虽然程序不长,但是基本上的脑力都是耗费在状态跳转图上面,如果状态跳转有少许差错就废了。

源代码下载

posted @ 2009-10-13 00:07  killkill  阅读(655)  评论(7编辑  收藏