вставка символа в строку
Задача простая — есть строка, например 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);
22.6 – Добавление данных к объектам std::string
Добавить строку в конец существующей строки легко, для этого необходимо воспользоваться функцией operator+= , append() или push_back() .
string& string::operator+= (const string& str)
string& string::append (const string& str)
Эти функции добавляют к строке символы str .
- Обе функции возвращают *this , поэтому их можно объединить в «цепочку».
- Обе функции вызывают исключение length_error , если результат превышает максимальное количество символов.
string sString("one"); sString += string(" two"); string sThree(" three"); sString.append(sThree); cout
one two three
Также есть вариант append() , который может добавлять подстроку:
string& string::append (const string& str, size_type index, size_type num)
Эта функция добавляет к строке num символов из строки str , начиная с index .
- Возвращает *this , поэтому ее можно вставить в «цепочку».
- Выбрасывает исключение out_of_range , если индекс выходит за пределы строки.
- Выбрасывает исключение length_error , если результат превышает максимальное количество символов.
string sString("one "); const string sTemp("twothreefour"); // добавляем подстроку строки sTemp, начиная с индекса 3, длиной 5 sString.append(sTemp, 3, 5); cout
one three
operator+= и append() также имеют версии, которые работают со строками в стиле C.
string& string::operator+= (const char* str)
string& string::append (const char* str)
Эти функции добавляют к строке символы str .
- Обе функции возвращают *this , поэтому их можно объединить в «цепочку».
- Обе функции вызывают исключение length_error , если результат превышает максимальное количество символов.
- str не должна быть равна nullptr .
string sString("one"); sString += " two"; sString.append(" three"); cout
one two three
Есть еще один дополнительный вариант append() , который работает со строками в стиле C:
string& string::append (const char* str, size_type len)
Добавляет в строку первые len символов строки str .
- Возвращает *this , поэтому ее можно вставить в «цепочку».
- Выбрасывает исключение length_error , если результат превышает максимальное количество символов.
- Игнорирует специальные символы (включая " ).
string sString("one "); sString.append("threefour", 5); cout
one three
Эта функция опасна, и ее использование не рекомендуется.
Также есть набор функций, которые добавляют символы. Обратите внимание, что имя неоператорной функции для добавления символа – push_back() , а не append() !
string& string::operator+= (char c)
void string::push_back (char c)
Эти функции добавляют к строке символ c .
- operator+= возвращает *this , чтобы его можно было вставить в «цепочку».
- Обе функции вызывают исключение length_error , если результат превышает максимальное количество символов.
string sString("one"); sString += ' '; sString.push_back('2'); cout
one 2
Вам может быть интересно, почему имя этой функции – push_back() , а не append() . Это следует соглашению об именах, используемому для стеков, где push_back() – это функция, которая добавляет один элемент в конец стека. Если вы представляете строку, как стек символов, то для добавления одного символа в ее конец имеет смысл использовать push_back() . Однако, на мой взгляд, отсутствие функции append() выбивается из последовательности!
Оказывается, есть функция append() для символов, которая выглядит так:
string& string::append (size_type num, char c)
Добавляет количество вхождений символа c в строку
- Возвращает *this , чтобы ее можно было вставить в «цепочку».
- Выдает исключение length_error , если результат превышает максимальное количество символов.
string sString("aaa"); sString.append(4, 'b'); cout
aaabbbb
Есть еще один, последний, вариант append() , который вы не поймете, если не знаете, что такое итераторы. Если вы не знакомы с итераторами, можете игнорировать эту функцию.
string& string::append (InputIterator start, InputIterator end)
Добавляет все символы из диапазона [ start , end ) (включая начало, но не включая конец)
- Возвращает *this , чтобы ее можно было вставить в «цепочку».
- Выдает исключение length_error , если результат превышает максимальное количество символов.
Урок №206. Вставка символов и строк в std::string
Вставлять символы/строки в std::string можно с помощью функции insert().
string& string::insert(size_type index, const string& str)
string& string::insert(size_type index, const char* str)
Обе функции вставляют символы/строки, начиная с определенного index std::string.
Генерируют исключение length_error, если результат превышает максимально допустимое количество символов.
Во второй версии функции insert() str не должен быть NULL .
std :: string sString ( "bbb" ) ;
std :: cout << sString << std :: endl ;
sString . insert ( 2 , std :: string ( "mmm" ) ) ;
std :: cout << sString << std :: endl ;
sString . insert ( 5 , "aaa" ) ;
std :: cout << sString << std :: endl ;
bbb
bbmmmb
bbmmmaaab
А вот версия функции insert(), которая позволяет вставить с определенного index std::string подстроку.
string& string::insert(size_type index, const string& str, size_type startindex, size_type num)
Эта функция вставляет с определенного index std::string указанное количество символов ( num ) строки str , начиная со startindex -а.
Возвращает скрытый указатель *this, что позволяет «связывать» объекты.
Генерирует исключение out_of_range, если index или startindex некорректны.
Генерирует исключение length_error, если результат превышает максимально допустимое количество символов.
std :: string sString ( "bbb" ) ;
const std :: string sInsert ( "012345" ) ;
sString . insert ( 1 , sInsert , 2 , 4 ) ; // вставляем подстроку sInsert длиной 4, начиная с символа под индексом 2, в строку sString, начиная с индекса 1
std :: cout << sString << std :: endl ;
А вот версия функции insert(), с помощью которой в std::string можно вставить часть строки C-style.
string& string::insert(size_type index, const char* str, size_type len)
Эта функция вставляет с определенного index std::string указанное количество символов ( len ) строки C-style str .
Возвращает скрытый указатель *this, что позволяет «связывать» объекты.
Генерирует исключение out_of_range, если index некорректен.
Генерирует исключение length_error, если результат превышает максимально допустимое количество символов.
Игнорирует специальные символы (такие как " ).
std :: string sString ( "bbb" ) ;
sString . insert ( 2 , "acdef" , 4 ) ;
std :: cout << sString << std :: endl ;
А вот версия функции insert(), которая вставляет в std::string один и тот же символ несколько раз.
string& string::insert(size_type index, size_type num, char c)
Эта функция вставляет с определенного index std::string указанное количество вхождений ( num ) символа c .
Возвращает скрытый указатель *this, что позволяет «связывать» объекты.
Генерирует исключение out_of_range, если index некорректен.
Генерирует исключение length_error, если результат превышает максимально допустимое количество символов.
std :: string sString ( "bbb" ) ;
sString . insert ( 2 , 3 , 'a' ) ;
std :: cout << sString << std :: endl ;
И, наконец, функция insert() имеет три разные версии, которые работают с итераторами.
void insert(iterator it, size_type num, char c)
iterator string::insert(iterator it, char c)
void string::insert(iterator it, InputIterator begin, InputIterator end)
Первая версия функции вставляет в std::string указанное количество вхождений ( num ) символа c перед итератором it .
Вторая версия функции вставляет в std::string одиночный символ c перед итератором it и возвращает итератор в позицию вставленного символа.
Третья версия функции вставляет в std::string все символы диапазона (begin, end) перед итератором it .
Все функции генерируют исключение length_error, если результат превышает максимально допустимое количество символов.
Строки в 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