C++. Сборник рецептов - Д. Стефенс
Шрифт:
Интервал:
Закладка:
min: 2.22507e-308
max: 1.79769e+308
long double:
min: 2.22507e-308
max: 1.79769e+308
unsigned short:
min: 0
max: 65535
unsigned int:
min: 0
max: 4294967295
unsigned long:
min: 0
max: 4294967295
ОбсуждениеПример 3.9 показывает простой пример получения минимального и максимального значений встроенных числовых типов. Шаблон класса numeric_limits имеет специализации для всех встроенных типов, включая как числовые, так и нечисловые типы. Стандарт требует, чтобы все типы, которые я использовал в примере 3.9, а также перечисленные далее, имели свою специализацию numeric_limits.
bool
char
signed char
unsigned char
wchar_t
min и max — это функции-члены numeric_limits типа static, которые возвращают наименьшее и наибольшее значения для типа переданного им параметра.
Глава 4
Строки и текст
4.0. Введение
Эта глава содержит рецепты работы со строками и текстовыми файлами. Большая часть программ на C++ независимо от сферы их применения в той или иной степени работает со строками и текстовыми файлами. Однако, несмотря на различия в сферах применения, требования к ним часто одни и те же: для строк — обрезка, дополнение, поиск, разбиение и т.п.; для текстовых файлов — перенос строк, переформатирование, чтение файлов с разделителями и др. Следующие рецепты предоставляют решения многих из часто встречающихся задач, не имеющих готовых решений в стандартной библиотеке С++.
Стандартная библиотека переносима, стандартизована и в общем случае не менее эффективна, чем самодельное решение, так что в следующих примерах я предпочитаю ее коду, написанному с нуля. Она содержит богатый раздел для работы со строками и текстом, большая часть которого заключена в шаблоне классов basic_string (для строк), basic_istream и basic_ostream (для входных и выходных текстовых потоков). Почти все методики, описанные в этой главе, используют или расширяют эти шаблоны классов. В тех случаях, когда они не делают того, что требуется, я использую другую часть стандартной библиотеки, содержащей общие готовые решения: алгоритмы и контейнеры.
Строки используют все, так что если что-то, что вам требуется, отсутствует в стандартной библиотеке, то велика вероятность, что это уже написано кем-то другим. Библиотека Boost String Algorithms (алгоритмы для работы со строками), написанная Паволом Дробой (Pavol Droba), заполняет большинство пробелов стандартной библиотеки, реализуя большую часть алгоритмов, которые могут понадобиться в различных ситуациях, и делает это переносимым и эффективным способом. Для получения дополнительной информации и документации по библиотеке String Algorithms обратитесь к проекту Boost по адресу www.boost.org. Библиотека String Algorithms и решения, приводимые в этой главе, в некоторых частях дублируют друг друга. В большинстве случаев я привожу примеры или, по крайней мере, упоминаю алгоритмы Boost связанные с приводимым решением.
Для большинства примеров приводится как версия с использованием шаблонов, так и без них. Это сделано по двум причинам. Во-первых, большая часть областей стандартной библиотеки, использующих символьные данные, — это шаблоны классов, параметризованных по типу символов — узкие (char) или широкие (wchar_t). Следуя этой модели, можно повысить совместимость программного обеспечения со стандартной библиотекой. Во-вторых, работаете ли вы со стандартной библиотекой или нет, шаблоны классов и функций предоставляют прекрасную возможность написания программного обеспечения, не привязанного к конкретной ситуации. Однако, если шаблоны не нужны, используйте нешаблонные версии, хотя, если вы новичок в шаблонах, я рекомендую вам поэкспериментировать с ними.
Стандартная библиотека очень активно использует шаблоны, а для того, чтобы оградить программистов от многословного синтаксиса шаблонов, использует typedef. В результате термины basic_string, string и wstring используются как взаимозаменяемые, поскольку то, что верно для одного из них, обычно верно и для двух других, string и wstring являются typedef для basic_string<char> и basic_string<wchar_t>.
Наконец, вы, вероятно, заметите, что ни один из рецептов этой главы не использует строк в стиле С, т.е. заканчивающихся нулем символьных массивов. Стандартная библиотека предоставляет такую богатую, эффективную и расширяемую поддержку строк С++, что использование строковых функций в стиле С (которые поддерживаются с целью обратной совместимости) — это уход от гибкости, безопасности и общей природы того, что дается бесплатно компилятором: классов строк С++.
4.1. Дополнение строк
ПроблемаТребуется «дополнить» — или заполнить - строку некоторым количеством символов до определенной длины. Например, может потребоваться дополнить строку "Chapter 1" точками до 20 символов в длину так, чтобы она выглядела как "Chapter 1...........".
РешениеДля дополнения строк начальными или концевыми символами используйте функции-члены (методы) insert и append класса string. Например, чтобы дополнить конец строки 20 символами X:
std::string s = "foo";
s.append(20 - s.length(), 'X');
Чтобы дополнить начало строки:
s.insert(s.begin(), 20 - s.length(), 'X');
ОбсуждениеРазница в использовании двух функций заключается в первом параметре insert. Это итератор, который указывает на символ, справа от которого требуется вставить новые символы. Метод begin возвращает итератор, указывающий на первый элемент строки, так что в этом примере последовательность символов добавляется слева от него. Параметры, общие для всех функций, — это количество раз, которое требуется повторить символ, и сам символ.
insert и append — это методы шаблона класса basic_string, описанного в заголовочном файле <string> (string — это typedef для basic_string<char>, a wstring — это typedef для basic_string<wchar_t>), так что они работают как для строк из узких, так и широких символов. Их использование по мере необходимости, как в предыдущем примере, прекрасно работает, но при использовании методов basic_string в собственных вспомогательных функциях общего назначения эти функции следует создавать, используя общий существующий дизайн стандартной библиотеки и шаблоны функций. Рассмотрим код примера 4.1, который определяет общий шаблон функции pad, который работает для строк типа basic_string.
Пример 4.1. Общий шаблон функции pad
#include <string>
#include <iostream>
using namespace std;
// Общий подход
template<typename >
void pad(basic_string<T>& s,
typename basic_string<T>::size_type n, T c) {
if (n > s.length())
s.append(n - s.length(), c);
}
int main() {
string s = "Appendix A";
wstring ws = L"Acknowledgments"; // "L" указывает, что
// этот литерал состоит из
pad(s, 20. "*"); // широких символов
pad(ws, 20, L'*');
// cout << s << std::endl; // He следует пытаться выполнить это
wcout << ws << std::endl; // одновременно
}
pad в примере 4.1 дополняет данную строку s до длины n, используя символ c. Так как шаблон функции использует параметризованный тип элементов строки (T), он будет работать для basic_string из любых символов: char, wchar_t или любых других, определенных пользователем.
4.2. Обрезка строк
ПроблемаТребуется обрезать несколько символов в конце или начале строки, обычно пробелов.
РешениеДля определения позиции строки, которую требуется удалить, используйте итераторы, а для ее удаления — метод erase. Пример 4.2 показывает функцию rtrim, которая удаляет символ в конце строки.
Пример 4.2. Обрезка символов строки
#include <string>
#include <iostream>
// Подход для строк из узких символов
void rtrim(std::string& s, char с) {
if (s.empty()) return;
std::string::iterator p;
for (p = s.end(); p != s.begin() && *--p == c;);
if (*p != c) p++;
s.erase(p, s.end());
}
int main() {
std::string s = "zoo";
rtrim(s, 'o');
std::cout << s << 'n';
}
ОбсуждениеПример 4.2 выполняет все необходимое для строк длины char, но работает только для них. Аналогично тому, что показано в примере 4.1, можно использовать общий дизайн basic_string и шаблон функции. Пример 4.3 использует для удаления символов в конце строки любого типа шаблон функции.