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

We use cookies. Read the Privacy and Cookie Policy

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) является ее эквивалентом для широких символов.

Каждая из этих функций преобразует регистр символа, используя текущие правила локали для преобразования регистра. Верхний и нижний регистры зависят от символов, используемых в текущей локали. Некоторые символы не имеют верхнего или нижнего регистра, и в этом случае указанные функции возвращают переданный им символ. За дополнительной информацией о локалях обратитесь к главе 13. Возможности C++ по работе с различными локалями довольно сложны, и я не могут уделить им сейчас достаточно места.

Выполнение собственно преобразования символов просто. Рассмотрим функцию toUpper из примера 4.20.

void toUpper(basic_string<char>& s) {

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

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

  *p = toupper(*p);

 }

}

Строка, выделенная жирным, выполняет всю работу. Версия для широких символов почти идентична.

void toUpper(basic_string<wchar_t>& s) {

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

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

  *p = towupper(*p);

 }

}

Я перегрузил toupper для различных типов символов потому, что не существует общей функции toupper, преобразующей регистр символов (при условии, что не используются возможности заголовочного файла <locale>, который я описываю ниже). Две простые функции, как приведенные выше, выполняют всю работу.

Однако есть и другой способ выполнить эту задачу, и фактором, оказывающим влияние на выбор этого способа, является необходимость использовать явные локали. Следующие версии toUpper и toLower преобразуют регистр строк независимо от типа их символов, но при условии, что указанная локаль (а по умолчанию текущая) поддерживает преобразование регистра для данного типа символов.

template<typename С>

void toUpper2(basic_string<C>& s, const locale& loc = locale()) {

 typename basic_string<C>::iterator p;

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

  *p = use_facet<ctype<C> >(loc).toupper(*p);

 }

}

template<typename C>

void tolower2(basic_string<C>& s, const locale& loc = locale()) {

 typename basic_string<C>::iterator p;

 for (p = s.begin(), p ! = s.end(++p) {

  *p = use_facet<ctype<C> >(loc).tolower(*p);

 }

}

Строки, выделенные жирным, выполняют всю работу. Функционально они работают точно так же, как и функции для верхнего и нижнего регистров, использованные в примере 4.20, за исключением того, что они используют для этого возможности интернационализации из заголовочного файла <locale>. За более подробным обсуждением локалей и возможностей интернационализации обратитесь к главе 13.