代码改变世界

趣味编程:从字符串中提取信息

2009-10-12 14:20 Jeffrey Zhao 阅读(...) 评论(...) 编辑 收藏

字符串解析是程序员工作中非常重要的一部分,也是非常考验编程能力的工作。基本上我在面试程序员的时候,一定会出一道编程题目作为考察的一方面,而这道题目有很大的可能性是做字符串的解析。例如,给出一个模式规则,要求写程序判断某个字符串是否符合特定格式。例如,要求将BB Code转化为HTML。而现在这个趣味编程题,来自于我目前正在进行的项目。因此从实用角度来说,也有一定现实意义。

这个标题基本上没有包含多少信息,不过我也实在不知道该如何描述这个问题。这个任务是要从一个字符串中提取一些信息,于是我们先来定义概念:

首先是“token”,token是最小的信息单元,我们可以把它当作是一个字符串来处理。而多个token则组成了一个token group,token group之间的各token使用“-”进行分割。例如,以下便定义一个了token group:

jeffz-hello-world

一个token group可以用一个字符串数组或列表来表示,例如上面的字符串则表示一个包含三个token的token group,分别是jeffz,hello和world。多个token group则可以组成一整个字符串信息,我们把它称为text。一个text中的各个token group使用“--”进行分割,例如:

group1-hello--group2-world

一个text可以认为是token group的数组或列表。因此,最终从一个text中提取到的信息,则可以用一个字符串数组的列表来表示。例如,以上的text的信息其实就类似于:

new List<string[]> { new string[] { "group1", "hello" }, new string[] { "group2", "world" } }

不过您想到这样一个问题:“-”是作为分割符使用的,但如果一个token中本身需要包含“-”又该如何呢?于是,我们又引入了单引号,被一组单引号包裹的token,其中所有的“-”被当作是普通的字符处理,不作为分隔符。例如:

jeffz-'hello-world'

这样一个字符串所表示的text,它包含一个token group,其中有两个token:

new List<string[]> { new string[] { "jeffz", "hello-world" } }

但是,既然单引号也有特殊含义了,那么一个token中又如何表示一个单引号呢?于是乎,我们再定义一个规则,如果一个token中需要包含单引号的话,我们需要使用单引号来包含这个token,并且token中的单引号变成两个单引号。例如:

jeffz-'hello''''world'

它所表示的数据即为:

new List<string[]> { new string[] { "jeffz", "hello''world" } }

text中包含四个单引号,但是表示的数据中只有两个单引号,这就是我们的“转义”规则。还有值得注意的是,如果token中需要包含单引号或“-”,那么这个token在表示的时候一定需要用一对单引号包裹起来——这也是为了“简化规则”。

这次的“趣味编程”便是希望写一个方法,从text中提取出“数据”,也就是一个List<string[]>,我们假设所有的输入都是正确的。

那么,这个规则又有什么含义呢?在我的项目中,这个字符串被当作是产品查询页面的URL,表示的自然是产品的查询条件。由于查询条件非常的丰富,还会根据不同的分类有所改变,因此在URL中表现查询条件非常的麻烦。例如,淘宝的查询页面URL便是这样的:

http://search1.taobao.com/browse/0/n-g,geytami-g,geytami-------1------7------------------4----0--------------------g,ojsxgzlsozsv64dsnfrwkwzvgaydalbzhe4tsxi---g,whflzr5rxy-------2-------b--40--coefp-0-all-0.htm?search_multi_condition=1&ssid=s1#ListView

但是,这个URL对于某个人来说几乎没有任何可读性。普通用户对此的关注度自然小很多,但是这样的URL也会给开发人员的工作造成不小的麻烦。在我看来,有一个相对易读的规则还是很重要的。此外,据说URL中的关键字对于SEO也很有帮助(当然这点我不确定)。因此,我们设计了本文这种“自洽”的数据表示方式。如果您足够“敏感”的话,会发现作为特殊字符的单引号或是“-”符号,它们在URL上是不需要转义的——这也是我们为它们赋予特殊含义的原因。

于是现在,我们便可以使用这样的URL字符串来表示一个查询条件了:

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

这个text拆开后的得到的数据便是:

new List<string[]>
{
    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" },
}

于是这个查询条件便是:CPU为3.0G,颜色为红、绿或黑,价格在5000到8000,重量在3千克内,并包含“levi's”关键字的……笔记本?

您也来试试看吧!(参考答案:上