Строки в C++
Для работы со строкам в C++ используется тип string . В разделе про потоки мы уже создавали объекты типа string и использовали их с операторами > . Рассмотрим этот тип подробнее.
Примеры создания объектов string :
string a; // пустая строка string b("abc"); // строка проинициализирована списком символов string c1(b); // c1 является копией b string c2 = b; // c2 является копией b string d('d', 10); // d = "dddddddddd"
Строки хранят в памяти последовательность объектов char , поэтому во многих случаях со строками можно работать как с массивом. Например, обращаться к символам через индекс.
string a("abz"); char c = a[2]; // 'z' char b = a.at(1); // 'b' a[2] = 'c'; // a = "abc"
Механизмы обращения к элементу через оператор [] и с помощью метода at() отличаются. В первом случае не происходит проверки того, что индекс меньше, чем длина строки. Если это условие не выполняется, то мы приходим к ситуации неопределенного поведения. Метод at() выполняет эту проверку и генерирует исключение в случае некорректного индекса. За это более безопасное поведение мы платим процессорным временем для дополнительной проверки.
По символам строки можно пройти в цикле:
string s("abcde"); for (char ch : s) cout <ch <' '; >
Узнать длину строки можно с помощью метода size() .
Строки можно конкатенировать с помощью оператора + или метода append :
string a("Hello, "); string b("world!"); string c = a + b; // "Hello, world!" a.append(b); // a = "Hello, world!" a += b; // a = "Hello, world!world!"
Добавить символ в конец строки можно с помощью метода push_back() , а удалить последний символ — с помощью метода pop_back() .
В типе string реализованы некоторые алгоритмы. Например, можно осуществлять поиск по строке:
string line("There are two needles in this haystack with needles."); string query("needle"); size_t found = line.find(query); // found = 14 if (found != string::npos) cout <"first '" <query <"' found at: " <found <'\n'; >
Метод find() возвращает позицию первого символа, которому соответствует совпадение. Если совпадений не найдено, возвращается специальная константа. size_t — это беззнаковый целочисленный тип.
Больше возможностей типа string можно найти в документации.
Документация
- en.cppreference.com/w/cpp/string/basic_string
- en.cppreference.com/w/cpp/header/cctype
Добавить char к char*
Можно ли добавить один символ типа char к строке char* и как это сделать?
Спасибо. Уже разобрался. Тему можно закрывать
4 ответа
12 ноября 2007 года
277 / / 11.10.2006
Можно ли добавить один символ типа char к строке char* и как это сделать?
Спасибо. Уже разобрался. Тему можно закрывать
Используй strcat(). (определен в string.h)
char *tmp = «ssss»;
char tmp1 = ‘d’;
strcat(tmp,&tmp1);
12 ноября 2007 года
4.8K / / 20.01.2000
Используй strcat(). (определен в string.h)
char *tmp = «ssss»;
char tmp1 = ‘d’;
strcat(tmp,&tmp1);
Ответ дважды неверный. Проверь и убедись.
13 ноября 2007 года
5.6K / / 13.08.2003
squirl@sqbuntu:~/Work/cpp$ cat test.c
#include
int main()
char *tmp = «ssss»;
char tmp1 = ‘d’;
strcat(tmp,&tmp1);
>
squirl@sqbuntu:~/Work/cpp$ gcc test.c
squirl@sqbuntu:~/Work/cpp$ ./a.out
Segmentation fault (core dumped)
squirl@sqbuntu:~/Work/cpp$
oops. ответ приравнивается к вредительскому, карается расстрелом
13 ноября 2007 года
4.8K / / 20.01.2000
Можно ли добавить один символ типа char к строке char* и как это сделать?
char* — это не строка, а всего лишь указатель на char.
Поэтому не ясно к чему ты собираешься прибавлять символ.
Указывает ли char* на область памяти достаточного размера, чтоб принять ещё один символ, или же твой char* указывает вообще на строковый литерал, как в неправильном примере NeO_u.
Вопрос слишком неконкретен, чтоб дать на него конкретный ответ.
вставка символа в строку
Задача простая — есть строка, например std::string(«sfsfsgsdshhdfjj»), необходимо вставить через каждый второй символ символ «-«.Не пойму как такое реализовать, пожалуйста подскажите.
Отслеживать
задан 28 апр 2016 в 5:19
1,973 3 3 золотых знака 17 17 серебряных знаков 34 34 бронзовых знака
Не правьте, пожалуйста, вопросы, изменяя метки, меняя точки на запятые и добавляя кавычки/ненужные метки, зарабатывая по +2 репутации. Вносите бОльшие изменения в вопрос, чтобы он был полезней, либо не меняйте его. Это не приносит пользы вопросам и сообществу в целом. Спасибо.
15 сен 2016 в 14:52
@Denis — пожалуйста! Исправлять орфографические ошибки и правила расстановки знаков препинания не нужно? Нет? Делать вопросы более понятными для всех не нужно. Я все исправляю по правилам форума. Я не просто зарабатываю 2 балла репутации — но и делаю полезное дело! И да — это приносит пользу сообществу!
15 сен 2016 в 16:14
Например, вот эта правка не несёт пользы вопросу — кавычки тут не нужны, как и точка после ссылки, есть даже причина для отклонения таких правок — «Правка никак не делает сообщения более простым к прочтению, не упрощает его поиск, точность или доступность. Изменения абсолютно излишни или явно ухудшают читаемость.»
16 сен 2016 в 6:55
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
Самый простой способ, пожалуй, — создать новую строку и посимвольно туда запихивать все это хозяйство.
string s("sfsfsgsdshhdfjj"); string d; for(auto c: s)
Update Как оказалось, не совсем верно понял, дефис надо через два на третий. Примерно так:
string d; for(size_t i = 0; i < s.length(); ++i) < d += s[i++]; if (i < s.length()) < d += s[i]; d += '-'; >>
Отслеживать
ответ дан 28 апр 2016 в 5:39
219k 15 15 золотых знаков 119 119 серебряных знаков 230 230 бронзовых знаков
я бы добавил: d.reserve(s.length()*2-1)
28 апр 2016 в 5:58
Да, согласен, несколько быстрее. Тут — ideone.com/Jmlwde — сравнение с резервированием, без и с методом вставкой.
28 апр 2016 в 6:17
А вообще, самый быстрый вот такой: ideone.com/B4C7xG объясняю почему: operator[] не выполняет никаких проверок вообще, а operator+= — выполняет. Как минимум — вдруг ёмкость исчерпалась, а значит нужно как бы и памяти добавить. Правило наименьшего оверхеда вкупе с наименьшим удивлением. Ваш вариант ещё и ошибку содержит: всегда добавляется — во конце, хотя не должен вообще. Пруф: ideone.com/VbE5RW
28 апр 2016 в 8:02
Решение @Harry быстрое, а если жалко памяти на два буффера сразу, то можно либо как у вас или так (дополнительной памяти O(1)):
// Резервируем память, что бы исключить реаллокации при вставке s.reserve(s.length()*3/2); for (size_t i = 2; i < s.length(); i+=2) s.insert(i++, 1, '-'); // инкремент тут нужен, что бы уйти с только что вставленного '-'
Минус: оно медленное за счёт того, что при каждой вставке нужно делать memmove / memcpy для оставшихся символов.
UPD: поправлено под условие (каждый второй символ)
UPD2: самый (пока?) шустрый вариант (дополнительной памяти O(n)):
string str; str.resize(s.length() * 3/2); size_t size = 0; for (size_t i = 0; i < s.length(); ++i) < str[size++] = s[i++]; if (i < s.length()) < str[size++] = s[i]; if (i != s.length() - 1) str[size++] = '-'; >> // ;-) str.resize(size);
Как добавить char в string c
Если надо добавить в конец строки другую строку, применяется метод append() , в который передается добавляемая строка:
#include #include int main() < std::string message< "hello">; message.append(" "); // добавляем пробел message.append("world"); // можно добавить по цепочке // message.append(" ").append("world"); std::cout
Вставка строки
Для вставки одной строки в другую применяется функция insert() . Она имеет несколько различных версий. Самая простая версия принимет индекс вставки и вставляемую строку:
#include #include int main() < std::string text ; std::string str ; text.insert(7, str); std::cout
В данном случае в строку text начиная с 7-го индекса вставляем строку str. В итоге переменная text будет равна "insert a string into a text".
Также можно вставлять строковый литерал:
std::string text ; text.insert(6, "C/"); // Hello C/C++
Можно вставлять часть подстроки:
std::string text ; std::string langs ; text.insert(6, langs, 5, 3); // Langs: C, C++
Здесь в text вставляем из переменной langs 3 символа с 5-го индекса, то есть подстроку " C,".
Среди других версий функции insert() также следует отметить версию, которая позволяет вставить определенный символ определенное число раз:
std::string text ; text.insert(8, 5, '*'); // Number: *****5678
В данном случае вставляем в строку text символ * 5 раз начиная с 8 индекса.
Замена подстроки
Для замены в строке некоторой части применяется функция replace() . Эта функция также имеет много версий, поэтому рассмотрим самые распространенные.
Самая простая версия принимает три параметра:
std::string &std::string::replace(size_t _Off, size_t _Nx, const char *_Ptr)
Первый параметр - представляет индекс, с которого надо заменять подстроку. Второй параметр - количество заменяемых символов. Третий параметр - на какую строку надо заменить. Пример:
#include #include int main() < std::string text ; text.replace(6, 4, "C++"); // Lang: C++ std::cout
Здесь в строке text заменяем 4 символа с 6-го индекса на строку "C++". Таким образом, из строки "Lang: Java" мы получим строку "Lang: C++".
В предыдущем примере символы заменялись на строковый литерал. Но также можно заменять на объект string:
std::string text ; std::string lang <"C++">; text.replace(6, 4, lang); // Lang: C++
Нередко стоит задача заменить какой-то определенную подстроку, индекс которой может быть не известен. В этом случае мы можем воспользоваться поиском в строке, чтобы найти индекс подстроки и ее размер. Например, возьмем текст "Hello, Tom!" и заменим подстроку "Tom" на "Bob":
#include #include int main() < std::string text ; const std::string separators ; // разделители слова size_t start ; // находим позицию подстроки size_t end; // Находим конец подстроки if(end == std::string::npos) // если разделители слова не найдены < end = text.length(); >text.replace(start, end - start, "Alice"); // заменяем подстроку std::cout
Здесь находим позицию первого символа подстроки "Tom" в тексте и сохраняем ее в переменную start. Символ, следующий за последним символом подстроки "Tom", находится путем поиска символа разделителя из строки separators с помощью функции find_first_of() . Далее используем найденные позиции индекса в replace() .
Однако в тексте может быть множество вхождений определенной подстроки (в нашем случае строки "Tom"), и может встать задача заменить все эти вхождения. Для этого мы можем использовать циклы:
#include #include int main() < std::string text ; std::string old_str; // какую подстроку заменить std::string new_str; // на какую строку заменить size_t start ; // находим позицию подстроки while (start != std::string::npos) // находим и заменяем все вхождения строки old_str < text.replace(start, old_str.length(), new_str); // Замена old_str на new_str start = text.find(old_str, start + new_str.length()); >std::cout
Здесь сначала находим индекс первого вхождения подстроки, которую надо заменить, и сохраняем этот индекс в переменную start. В цикле заменяем последовательно все вхождения подстроки. После каждой замены находим индекс следующего вхождения, сохраняем его в переменную start и повторяем цикл. Когда больше нет вхождений подстроки в текст, start будет содержать значение std::string::npos , что завершает цикл.
Из других версий функции replace() можно выделить функцию, которая заменяет подстроку определенным символом, который повторяется определенное количество раз:
std::string text ; text.replace(9, 6, 5, '*'); // Phone: +1*****8901
Здесь заменяет в строке text 6 символов начиная с 9-го индекса на 5 символов *.
Удаление символов
Если надо не просто заменить символы, а удалить их из текста, также можно использовать функцию replace() - в этом случае удаляемые символы фактически заменяются на пустую строку:
#include #include int main() < std::string text ; const std::string empty; text.replace(5, 4, empty); // Замена "Tom" на пустую строку std::cout
Однако С++ также предоставляет для удаления символов специальную функцию - erase() . В качестве параметров она принимает начальный индекс удаления и количество удаляемых символов:
#include #include int main() < std::string text ; text.erase(5, 4); // удаляем 4 символа с 5-го индекса std::cout
Аналогично можно удалить все вхождения определенной подстроки:
#include #include int main() < std::string text ; std::string to_delete; // какую подстроку удалить size_t start ; // находим позицию подстроки while (start != std::string::npos) // находим и удаляем все вхождения to_delete < text.erase(start, to_delete.length()); start = text.find(to_delete, start + to_delete.length()); >std::cout
Функция erase() имеет ряд дополнительных версий. Так, можно оставить определенное количество символов с начала строки, а остальные удалить:
std::string text ; text.erase(5); // удаляем все кроме первых 5 символов - остается "Hello"
Если в функцию не передается никаких параметров, то она удаляет все символы, и в результате получаем пустую строку:
std::string text ; text.erase(); // пустая строка
Стоит отметить, что в стандарт С++20 была добавлена функция std::erase() , которая удаляет все вхождения определенного символа в строке:
#include #include int main() < std::string text ; std::erase(text, 'T'); // Удаляем символ T std::cout
В данном случае удаляем из строки text символ T.