Рейтинговые книги
Читем онлайн C++. Сборник рецептов - Д. Стефенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 41 42 43 44 45 46 47 48 49 ... 136

Пример 4.16. Подсчет уникальных символов

#include <string>

#include <iostream>

template<typename T>

int countUnique(const std::basic_string<T>& s) {

 using std::basic_string;

 basic_string<T> chars;

 for (typename basic_string<T>::const_iterator p = s.begin();

  p != s.end(); ++p) {

  if (chars.find(*p) == basic.string<T>::npos)

  chars += *p;

 }

 return(chars.length());

}

int main() {

 std: :string s = "Abracadabra'";

 std::cout << countUnique(s) << 'n';

}

Функции поиска очень часто оказываются полезными. Когда требуется найти что- либо в строке типа string, они должны быть первым, что следует использовать.

4.10. Поиск n-го вхождения подстроки

Проблема

Имея источник source и шаблон pattern типа string, требуется найти n-е вхождение pattern в source.

Решение

Для поиска последовательных вхождений искомой подстроки используйте метод find. Пример 4.17 содержит простую функцию nthSubstr.

Пример 4.17. Поиск n-го вхождения подстроки

#include <string>

#include <iostream>

using namespace std;

int nthSubstr(int n, const strings s,

 const strings p) {

 string::size_type i = s.find(p); // Найти первое вхождение

 int j;

 for (j = 1; j < n && i != string::npos; ++j)

  i = s.find(p, i+1); // Найти следующее вхождение

 if (j == n) return(i);

 else return(-1);

}

int main() (

 string s = "the wind, the sea, the sky, the trees";

 string p = "the";

 cout << nthSubstr(1, s, p) << 'n';

 cout << nthSubstr(2, s, p) << 'n';

 cout << nthSubstr(5, s, p) << 'n';

}

Обсуждение

В функцию nthSubstr, имеющую вид, показанный в примере 4.17, можно внести пару улучшений. Во-первых, ее можно сделать общей, сделав из нее вместо обычной функции шаблон функции. Во-вторых, можно добавить параметр, позволяющий учитывать подстроки, которые перекрываются друг с другом. Под перекрывающимися подстроками я понимаю такие, у которых начало строки соответствует части конца такой же строки, как в строке «abracadabra», где последние четыре символа такие же, как и первые четыре. Это демонстрируется в примере 4.18.

Пример 4.18. Улучшенная версия nthSubstr

#include <string>

#include <iostream>

using namespace std;

template<typename T>

int nthSubstrg(int n, const basic_string<T>& s,

 const basic_string<T>& p, bool repeats = false) {

 string::size_type i = s.find(p);

 string::size_type adv = (repeats) ? 1 : p.length();

 int j;

 for (j = 1; j < n && i != basic_string<T>::npos; ++j)

  i = s.find(p, i+adv);

 if (j == n)

  return(i);

 else

  return(-1);

}

int main() {

 string s = AGATGCCATATATATACGATATCCTTA";

 string p = "ATAT";

 cout << p << " без повторений встречается в позиции "

  << nthSubstrg(3, s, p) << 'n';

 cout << p << " с повторениями встречается в позиции "

  << nthSubstrg(3, s, p, true) << 'n';

}

Вывод для строк, использованных в примере 4.18, выглядит так.

ATAT без повторений встречается в позиции 18

ATAT с повторениями встречается в позиции 11

Смотри также

Рецепт 4.9.

4.11. Удаление подстроки из строки

Проблема

Требуется удалить из строки подстроку.

Решение

Используйте методы basic_string find, erase и length:

std::string t = "Banana Republic";

std::string s = "nana";

std::string::size_type i = t.find(s);

if (i != std::string::npos) t.erase(i, s.length());

Этот код удаляет s.length() элементов, начиная с индекса, по которому find находит первое вхождение подстроки.

Обсуждение

На практике встречается огромное количество вариаций на тему поиска и удаления подстрок. Например, может потребоваться удалить все вхождения подстроки, а не одно из них. Или только последнее. Или седьмое. Каждый раз действия будут одни и те же: найдите индекс начала шаблона, который требуется удалить, затем вызовите erase для этого индекса и n последующих символов, где n — это длина строки шаблона. За описанием различных методов поиска подстрок обратитесь к рецепту 4.9.

Также велика вероятность, что вам потребуется сделать функцию удаления обобщенной, так чтобы ее можно было использовать с любыми типами символов. Пример 4.19 предлагает общую версию, которая удаляет все вхождения шаблона в строке.

Пример 4.19. Удаление всех подстрок из строки (обобщенная версия)

#include <string>

#include <iostream>

using namespace std;

template<typename T>

void removeSubstrs(basic_string<T>& s,

 const basic_string<T>& p) {

 basic_string<T>::size_type n = p.length();

 for (basic_string<T>::size_type i = s.find(p);

  i != basic_string<T>::npos; i = s.find(p))

  s.erase(i, n);

}

int main() {

 string s = "One fish, two fish, red fish, blue fish";

 string p = "fish";

 removeSubstrs(s, p);

 cout << s << 'n';

}

Здесь всю важную работу выполняет метод erase basic_string. В <string> он перегружен три раза. Использованная в примере 4.19 версия принимает индекс, с которого требуется начать удаление, и число удаляемых символов. Другая версия принимает в качестве аргументов начальный и конечный итераторы, а также есть версия, которая принимает единственный итератор и удаляет элемент, на который он указывает. Чтобы обеспечить оптимальную производительность при планировании удаления нескольких последовательных элементов, используйте первые две версии и не вызывайте s.erase(iter) несколько раз для удаления каждого из идущих подряд элементов. Другими словами, используйте методы, работающие с диапазонами, а не с одним элементом, особенно в случае тех методов, которые изменяют содержимое строки (или последовательности). В этом случае вы избежите дополнительных вызовов функции erase для каждого элемента последовательности и позволите реализации string более грамотно управлять ее содержимым.

4.12. Преобразование строки к нижнему или верхнему регистру

Проблема

Имеется строка, которую требуется преобразовать к нижнему или верхнему регистру.

Решение

Для преобразования символов к нижнему или верхнему регистру используйте функции toupper и tolower из заголовочного файла <cctype>. Пример 4.20 показывает, как использовать эти функции. Смотри также обсуждение альтернативных методик.

Пример 4.20. Преобразование регистра строки

#include <iostream>

#include <string>

#include <cctype>

#include <cwctype>

#include <stdexcept>

using namespace std;

void toUpper(basic_string<char>& s) {

 for (basic_string<char>::iterator p = s.begin();

 p != s.end(); ++p) {

  *p = toupper(*p); // toupper is for char

 }

}

void toUpper<basic_string<wchar_t>& s) {

 for (basic_string<wchar_t>::iterator p = s.begin();

  p != s.end(); ++p) {

  *p = towupper(*p); // towupper is for wchar_t

 }

}

void toLower(basic_string<char>& s) {

 for (basic_string<char>::iterator p = s.begin();

  p != s.end(); ++p) {

  *p = tolower(*p);

 }

}

void toLower(basic_string<wchar_t>& s) {

 for (basic_string<wchar_t>::iterator p = s.begin();

  p != s.end(); ++p) {

  *p = towlower(*p);

}

int main() {

 string s = "shazam";

 wstring ws = L"wham";

 toUpper(s); toUpper(ws);

 cout << "s = " << s << endl;

 wcout << "ws = " << ws << endl;

 toLower(s);

 toLower(ws);

 cout << "s = " << s << endl;

 wcout << "ws = " << ws << endl;

}

Этот код производит следующий вывод.

s = SHAZAM

ws = WHAM

s = shazam

ws = wham

Обсуждение

Кто-то может подумать, что стандартный класс string содержит метод, преобразующий всю строку к верхнему или нижнему регистру, но на самом деле это не так. Если требуется преобразовать строку символов к верхнему или нижнему регистру, это требуется делать самостоятельно.

Неудивительно, что имеется несколько способов преобразования регистра строки (и когда я говорю «строки», то имею в виду последовательность символов как узких, так и широких). Простейшим способом сделать это является использование одной из четырех функций преобразования символов toupper, towupper, tolower и towlower. Первая форма этих функций работает с узкими символами, а вторая форма (с дополнительной буквой w) является ее эквивалентом для широких символов.

1 ... 41 42 43 44 45 46 47 48 49 ... 136
На этой странице вы можете бесплатно читать книгу C++. Сборник рецептов - Д. Стефенс бесплатно.

Оставить комментарий