Статьи

С ++ Кратко: Строки

Строки являются одной из тех проблем в C и C ++. В ранние времена языков все строки были символьными массивами, обычно это 7-битный ASCII (хотя, возможно, EBCDIC на мэйнфреймах IBM, на которые был перенесен C). Затем возникла путаница специфичных для ОС обходных путей, таких как кодовые страницы, для учета языков с символами, отсутствующими в английском алфавите. После периода хаоса пришел Unicode. Тогда Юникод. И снова Unicode. И еще несколько юникодов здесь и там, что является корнем проблемы сегодня.

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

Тогда есть схемы кодирования, откуда берутся деления. В Unicode есть 1114,112 кодовых точек. Как вы их представляете? Ответом были схемы кодирования. UTF-16 был первым. Позднее последовали UTF-8 и UTF-32. Есть также проблемы с порядком байтов с некоторыми из них.

Другие форматы приходили и уходили, некоторые из которых никогда не были частью Unicode.

В конечном итоге Windows приняла UTF-16, как и .NET и Java. Многие GNU / Linux и другие UNIX-подобные системы приняли UTF-8. Некоторые UNIX-подобные системы используют UTF-32. Некоторые могут использовать UTF-16. Сеть в основном использует UTF-8, поскольку намеренный дизайн этой кодировки в основном обратно совместим с ASCII. Пока вы работаете в одной системе, все хорошо. Когда вы пытаетесь стать кроссплатформенным, вещи могут стать более запутанными.

Строки char * (указатели на массивы char) изначально означали строки ASCII. Теперь они иногда означают ASCII, но чаще они означают UTF-8. Это особенно верно в мире UNIX.

При программировании для Windows, как правило, следует предполагать, что строка char * является строкой ASCII или строкой кодовой страницы. Кодовые страницы используют дополнительный бит, оставшийся от 7-битного ASCII, чтобы добавить еще 128 символов, создавая таким образом много локализованного текста, который все еще умещается в один байт на символ.

Строки wchar_t* (указатели на массивы wchar_t , также называемые широкими символами) используют другой, зависящий от реализации набор символов. В Windows это означает 16-битное значение, которое используется для UTF-16. Вы всегда должны работать с wchar_t как вашим собственным символьным типом для Windows, если только вам не нужно поддерживать действительно очень старые версии ОС (то есть старые серии Windows 9X).

Когда вы пишете строковую константу широких символов в коде, вы начинаете с двойных кавычек, const wchar_t* s = L"Hello World"; L. Например: const wchar_t* s = L"Hello World"; , Если вам нужен только один символ, вы снова используете L, но с одинарными кавычками: wchar_t ch = L'A' ;.

Классы std::string и std::wstring находятся в заголовочном файле <string>. Как вы можете себе представить, std::string соответствует char* а std::wstring соответствует wchar_t* .

Эти классы предоставляют удобный способ хранения строк переменной длины и должны использоваться для переменных членов класса вместо их соответствующих необработанных указателей (char * и wchar_t *). Вы должны использовать только необработанные указатели для передачи строк в качестве аргументов, и только в том случае, если строка будет использоваться как есть или локально скопирована в один из этих типов строк.

В любом случае функция должна принимать указатель на строку как указатель на const (например, const wchar_t* someStr ). В конце концов, указатели не несут таких же затрат на создание и уничтожение, как std :: string и std :: wstring. Использование указателя для const гарантирует, что функция не будет случайно изменять данные или пытаться освободить указанную память.

Чтобы получить указатель на const для содержимого одного из них, вызовите его функцию-член c_str. Обратите внимание, что возвращаемый указатель указывает на const, так как данные не должны быть изменены, а удаление не должно вызываться для указателя. Память по-прежнему принадлежит и управляется базовым экземпляром std :: string или std :: wstring. Это также означает, что если базовый экземпляр уничтожен, указатель, который дает вам c_str, становится недействительным, поэтому, если вам нужны строковые данные вне области функции, в которую они передаются, вы всегда должны хранить строковые данные в один из этих типов, а не хранение указателя напрямую.

Чтобы добавить текст, используйте функцию члена добавления.

Чтобы увидеть, встречается ли определенная последовательность символов в строке, используйте функцию-член find или один из ее более конкретных вариантов, например find_first_of. Если последовательность отсутствует в строке, возвращаемое значение будет равно std::npos . В противном случае это будет индекс соответствующей начальной точки последовательности.

Чтобы получить подстроку, используйте функцию-член substr, передав ей начальный индекс, начинающийся с нуля, и количество элементов (т. Е. Количество символов char или wchar_t) для копирования. Он вернет std :: string или std :: wstring, не позволяя переполнить буфер, передавая неточный счет или неправильный начальный индекс.

Существуют и другие полезные методы, все из которых задокументированы как часть класса basic_string, который является шаблоном класса, для которого std :: string и std :: wstring являются предопределенными специализациями.

Класс std::wstringstream (также есть std::stringstream ) аналогичен классу .NET StringBuilder. Он может использоваться практически так же, как и любой другой поток стандартной библиотеки C ++. Я считаю этот тип очень полезным для создания строки внутри функции-члена, которая затем будет сохранена в члене класса std::wstring .

Пример ее использования см. В Toppings::GetString члене Toppings::GetString в файле ConstructorsSample \ Toppings.h. Вот его код, просто как переподготовка:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
const wchar_t* GetString(void)
       {
           if (m_toppings == None)
           {
               m_toppingsString = L»None»;
               return m_toppingsString.c_str();
           }
           bool addSpace = false;
           std::wstringstream wstrstream;
           if (m_toppings & HotFudge)
           {
               if (addSpace)
               {
                   wstrstream << L» «;
               }
               wstrstream << L»Hot Fudge»;
               addSpace = true;
           }
           if (m_toppings & RaspberrySyrup)
           {
               if (addSpace)
               {
                   wstrstream << L» «;
               }
               wstrstream << L»Raspberry Syrup»;
               addSpace = true;
           }
           if (m_toppings & CrushedWalnuts)
           {
               if (addSpace)
               {
                   wstrstream << L» «;
               }
               wstrstream << L»Crushed Walnuts»;
               addSpace = true;
           }
           if (m_toppings & WhippedCream)
           {
               if (addSpace)
               {
                   wstrstream << L» «;
               }
               wstrstream << L»Whipped Cream»;
               addSpace = true;
           }
           if (m_toppings & Cherry)
           {
               if (addSpace)
               {
                   wstrstream << L» «;
               }
               wstrstream << L»Cherry»;
               addSpace = true;
           }
           m_toppingsString = std::wstring(wstrstream.str());
           return m_toppingsString.c_str();
       }

Как я упоминал во введении, история строк не очень приятна, но я надеюсь, что эта статья дала вам правильное понимание строк в C ++. Следующая часть этой серии статей посвящена распространенным идиомам в C ++.

Этот урок представляет собой главу из C ++ Succinctly , бесплатной книги от команды Syncfusion .