在1.4节,我们把“解析”定义为分析自然语言句子或形式语言语句之结构的过程。比如,编译器在将代码翻译成机器语言程序之前必须先进行解析。
此外,当你从文件或键盘读取输入时,一般也需要进行解析,以提取想要的信息并发现错误。
例如,我有一个文件distances,其中包含了美国主要城市之间的距离信息。这些信息是我从一个随机选择的网页(http://www.jaring.my/usiskl/usa/distance.html)中得到的,所以数据可能不是很准确,不过这也没什么关系。文件格式看起来是这样的:
"Atlanta" "Chicago" 700
"Atlanta" "Boston" 1100
"Atlanta" "Chicago" 700
"Atlanta" "Dallas" 800
"Atlanta" "Denver" 1450
"Atlanta" "Detroit" 750
"Atlanta" "Orlando" 400
文件中的每一行包含了两个城市的名字以及它们之间的距离,其中城市名用引号标记,距离以英里为单位。引号是有用的,因为它能让我们很容易地处理多于一个单词的城市名,如”San Francisco“(旧金山)。
通过搜索一行输入中的引号,我们能找到每个城市在该行的开始和结束位置。不过查找引号这样的特殊字符可能让人有点困惑,因为引号是C++中用于标识字符串的特殊字符。
要找到引号第一次出现的位置,应该这样写:
int index = line.find (’\"’);
参数看起来有点乱,不过它就是表示双引号字符。最外层的单引号依然用于表示这是个字符值。反斜杠(\)说明我们想使用下一个字符的字面意义。 所以序列 \" 表示双引号,而序列 \’表示单引号。有趣的是, 序列\表示一个反斜杠。第一个反斜杠指示我们要认真对待第二个反斜杠。
解析输入行由这几部分组成:找到每个城市名在该行中的开始和结束位置,使用substr函数提取城市和距离信息。substr是apstring的成员函数之一,它有两个参数,分别是子串的起始位置和长度。
void processLine (const apstring& line)
{
// 我们要查找的字符是引号
char quote = ’\"’;
// 将引号的索引保存在一个向量中
apvector<int> quoteIndex (4);
// 使用内置的find函数查找到第一个引号
quoteIndex[0] = line.find (quote);
// 使用第7章定义的find函数查找其他引号
for (int i=1; i<4; i++) {
quoteIndex[i] = find (line, quote, quoteIndex[i-1]+1);
}
// 将一行的内容分割成子串
int len1 = quoteIndex[1] - quoteIndex[0] - 1;
apstring city1 = line.substr (quoteIndex[0]+1, len1);
int len2 = quoteIndex[3] - quoteIndex[2] - 1;
apstring city2 = line.substr (quoteIndex[2]+1, len2);
int len3 = line.length() - quoteIndex[2] - 1;
apstring distString = line.substr (quoteIndex[3]+1, len3);
// 输出提取的信息
cout << city1 << "\t" << city2 << "\t" << distString << endl;
}
当然,我们真正想要的并不仅仅是提取并显示信息,不过这是一个好的开始。