8.11.5 搜索字符串(5)
示例说明
在本示例中使用getline()从cin中读取输入,将终止字符指定为一个星号。这样允许输入任意行代码。从字符串对象text的输入中提取单个单词,并存储在words数组中。这是通过while循环完成的。
从text中提取单词的第一步是找到单词的第一个字符的索引位置:
- start = text.find_first_not_of(separators, offset); // Find non-separator
- if(string::npos == start) // If we did not find it, we are done
- break;
- offset = start + 1; // Move past character found
调用find_first_not_of()函数返回位置offset中第一个不是separators中的字符之一的字符的索引位置。这里可以使用find_first_of()函数来搜索A~Z、a~z中的任何字符来得到同样的结果。当提取了最后一个单词后,搜索会到达字符串的末尾,而没有发现任何匹配的字符,因此通过比较返回的值与string::npos来进行测试。如果它是字符串的末尾,就提取所有单词,因此退出循环。在任何其他情况下,就在发现的字符后面一个字符处设置offset。
下一步是搜索任何分隔符字符:
- end = text.find_first_of(separators,offset); // Find separator
- if(string::npos == end) // If it's the end of the string
- { // current word is last in string
- offset = end; // We use offset to end loop later
- end = text.length(); // Set end as 1 past last character
- }
- else
- offset = end + 1; // Move past character found
这段代码从索引位置offset处搜索任何分隔符,这是单词的第一个字符后面的字符,因此通常将会发现分隔符是单词的最后一个字符后面的字符。当单词是文本中的最后一个词,而且该单词的最后一个字符后面没有分隔符时,函数就会返回string::npos,因此我们这样处理此类情况:将end设置为字符串中最后一个字符后面的字符,并将offset设置为string::npos。以后在提取当前单词之后的循环中会测试offset变量,来判断是否应结束循环。
单词的提取并不难:
- words[nwords] = text.substr(start, end-start); // Extract the word
substr()函数在text中从start处的字符开始提取end-start个字符。单词的长度是end-start,因为start是第一个字符,而end是单词中的最后一个字符后面的那个字符。
while循环体的其余部分以前面介绍的方式跟踪最大单词长度,检查字符串结束条件,并检查words数组有没有满。
这些单词在一个for循环中输出,它们在words数组中的所有元素上迭代。循环中的if语句用来计数重复的单词:
- if(0 == count)
- count = 1;
- if(i < nwords-2 && words[i] == words[i+1])
- {
- ++count;
- continue;
- }
count变量记录重复的单词个数,因此它的最小值总是为1。在循环的末尾,当写出一个单词和它的计数时,将count设置为0。它充当一个指示器,表示开始计数新的单词,因此当count为0时,第一个if语句将它设置为1,否则保留当前值。
第二个if语句检查下一个单词与当前单词是否相同,如果相同,则递增count,并跳过当前循环迭代的其余部分。该机制用count累计单词的重复次数。循环条件也检查索引i是否小于nwords-2,若当前单词是数组中的最后一个单词,就不用检查下一个单词。因此,当下一个单词与当前单词不同,或者当前单词是数组中的最后一个单词时,仅输出一个单词和它的计数。
for循环中的最后一步是输出一个单词和它的计数:
- cout << setiosflags(ios::left) // Output word left-justified
- << setw(maxwidth+2) << words[i];
- cout << resetiosflags(ios::right) // and word count right-justified
- << setw(5) << count << endl;
- count = 0;
该输出语句将单词在比最长单词长两个字符的字段宽度中左对齐。计数输出是在宽度为5的字段宽度中右对齐。