8.8.5 搜索字符串(2)
对于find_fisrt_of()和find_last_of()函数的所有版本,如果没有发现匹配的字符,都会返回string::npos。
使用与上一个代码片段中相同的字符串,可以看到find_last_of()函数对字符串"had"所执行的搜索。
- size_t count = 0;
- size_t offset = string::npos;
- while(true)
- {
- offset = str.find_last_of(substr, offset);
- if(offset == string::npos)
- break;
- --offset;
- ++count;
- }
- cout << endl << " Characters from the string \"" << substr
- << "\" were found " << count << " times in the string above."
- << endl;
这次我们从字符串末尾索引位置string::npos开始向后搜索,因为这是默认开始位置。该代码片段的输出为:
- The string to be searched is:
- Smith, where Jones had had "had had", "had had"
had. "Had had" had had - the examiners' approval.
-
- Characters from the string "had" were found 38
times in the string above.
结果应当不出意料。记住,我们在搜索字符串str中出现的"had"中的任何字符。"Had"和"had"单词中有32个,其他单词中有6个。因为我们在沿着字符串向后搜索,因此当我们发现一个字符时,递减循环内的offset。
最后一组搜索函数是find_first_not_of()和find_last_not_of()函数的各个版本,如表8-5所示。
表 8-5
|
函 数< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
说 明 |
|
find_first_not_of(char ch,
size_t offset=0) |
在string对象中搜索从offset
索引位置开始出现的不是字符ch
的字符,并返回发现字符的索引
位置值,类型为size_t。如果省略
第二个实参,offset的默认值就为0 |
|
find_first_not_of(
char* pstr,
size_t offset=0) |
在string对象中搜索从offset索引
位置开始第一次出现的不在以空字
符结尾的字符串pstring中的字符,
并返回发现字符的索引位置值,类型
为size_t。如果省略第二个实参,
offset的默认值就为0 |
|
find_first_not_of(
char* pstr,
size_t offset,
size_t count) |
在string对象中搜索从offset索引
位置开始第一次出现的不在以空字
符结尾的字符串pstring中的前
count个字符中的任何字符,并返
回发现字符的索引位置值,类型为size_t |
|
find_first_not_of(
string str,
size_t offset=0) |
在string对象中搜索从offset索引位
置开始第一次出现的不在字符串str
中的任何字符,并返回发现字符的索
引位置值,类型为size_t。如果省略
第二个实参,offset的默认值就为0 |
|
find_last_not_of(char ch,
size_t offset=npos) |
在string对象中向后搜索从offset索
引位置开始最后一次出现的不是字符
ch的字符,并返回发现该字符的索
引位置值,类型为size_t。如果省略
第二个实参,offset的默认值就为字
符串的末尾字符nops |
|
find_last_not_of(char* pstr,
size_t offset=npos) |
在string对象中向后搜索从offset索
引位置开始最后一次出现的不在以
空字符结尾的字符串pstr中的任何
字符,并返回发现该字符的索引位置
值,类型为size_t。如果省略第二个
实参,offset的默认值就为字符串的
末尾字符nops |
|
find_last_not_of(char* pstr,
size_t offset,
size_t count) |
在string对象中向后搜索从offset索
引位置开始最后一次出现的不在以
空字符结尾的字符串pstr中的前
count个字符中的字符。该函数返回
发现该字符的索引位置值,类型为size_t |
|
find_last_not_of(string str,
size_t offset=npos) |
在string对象中向后搜索从offset索
引位置开始最后一次出现的不在字
符串str中的任何字符,并返回发现
该字符的索引位置值,类型为size_t。
如果省略第二个实参,offset的默认
值就为字符串的末尾字符nops |
对于前面的这些搜索函数,如果没有搜索到匹配的字符,将返回string::npos。这些函数有很多用法,通常用来在字符串中查找可能由各种字符隔开的令牌(token)。例如,用空格和标点符号隔开的单词组成的文本,因此,我们可以用这些函数在文本块中查找单词。下面举例说明其工作过程。
试一试:排序文本中的单词
本例将读一个文本块,然后提取一些单词并以升序输出它们。在此将使用某种低效的冒泡排序函数,这在Ex8_10中可以看到。在第10章将使用一个好用得多的库函数来排序,不过在使用那个函数前我们需要先了解一些别的知识。该程序也会计算每个单词出现了多少次,并输出各个单词的个数。因此,这样的分析称为校准(collocation)。代码如下:
- // Ex8_11.cpp
- // Extracting words from text
- #include <iostream>
- #include <iomanip>
- #include <string>
- using std::cin;
- using std::cout;
- using std::endl;
- using std::ios;
- using std::setiosflags;
- using std::resetiosflags;
- using std::setw;
- using std::string;
-
- // Sort an array of string objects
- string* sort(string* strings, size_t count)
- {
- bool swapped = false;
- while(true)
- {
- for(size_t i = 0 ; i<count-1 ; i++)
- {
- if(strings[i] > strings[i+1])
- {
- swapped = true;
- strings[i].swap(strings[i+1]);
- }
- }
- if(!swapped)
- break;
- swapped = false;
- }
- return strings;
- }
-
- int main()
- {
- const size_t maxwords(100);
- string words[maxwords];
- string text;
- string separators(" \".,:;! ()\n");
- size_t nwords = 0;
- size_t maxwidth = 0;
-
- cout << "Enter some text on as many lines as you wish."
- << endl << "Terminate the input with an asterisk:" << endl;
-
- getline(cin, text, '*');
-
- size_t start(0), end(0), offset(0);
// Record start & end of word & offset - while(true)
- {
- // Find first character of a word
- start = text.find_first_not_of(separators, offset);
-
// Find non-separator - if(start == string::npos) // If we did not find it, we are done
- break;
- offset = start + 1; // Move past character found
-
- // Find first separator past end of current word
- end = text.find_first_of(separators,offset);
// Find separator - if(end == string::npos) // 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
-
- words[nwords] = text.substr(start, end-start);
// Extract the word -
- // Keep track of longest word
- if(maxwidth < words[nwords].length())
- maxwidth = words[nwords].length();
-
- if(offset == string::npos)// If we reached the end of the string
- break; // We are done
-
- if(++nwords == maxwords) // Check for array full
- {
- cout << endl << "Maximum number of words reached."
- << endl << "Processing what we have." << endl;
- break;
- }
- }
-
- sort(words, nwords);
-
- cout << endl
- << "In ascending sequence, the words in the text are:"
- << endl;
-
- size_t count(0); // Count of duplicate words
- // Output words and number of occurrences
- for(size_t i = 0 ; i<nwords ; i++)
- {
- if(count == 0)
- count = 1;
- if(i < nwords-2 && words[i] == words[i+1])
- {
- ++count;
- continue;
- }
- 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;
- }
- cout << endl;
- return 0;
- }