Как удалить подстроку из строки методом erase? c++ [закрыт]
Закрыт. Этот вопрос не по теме. Ответы на него в данный момент не принимаются.
Вопросы с просьбами помочь с отладкой («почему этот код не работает?») должны включать желаемое поведение, конкретную проблему или ошибку и минимальный код для её воспроизведения прямо в вопросе. Вопросы без явного описания проблемы бесполезны для остальных посетителей. См. Как создать минимальный, самодостаточный и воспроизводимый пример.
Закрыт 2 года назад .
Для заполнения стека нужно ввести «push какое-то число«». Я записываю это в строку, затем пытаюсь удалить из нее подстроку начиная с 0-ого символа по 4-ый символ, чтобы строка содержала только число, которое я позже преобразую к int и благополучно запихаю в стек. Что я делаю не так? Пробовал также str = str.erase (0,3)
#include #include int main() < using namespace std; string str = ""; cin >> str; str.erase(0, 4); cout
Как работает erase в c
Идиома remove-erase idiom призвана решить проблему удаления элементов из контейнера, поскольку данная проблема может представлять нетривиальную задачу, чреватую возникновением ошибок. Данная идиома предполагает применение алгоритма remove() или remove_if() , за которым следует вызов функции erase() контейнера.
При применении алгоритмов remove() и remove_if() те элементы, которые надо сохранить, помещаются в начало контейнера, а функции remove() и remove_if() возвращают итератор на первый удаляемый элемент. Затем этот итератор передается в функцию erase() , которая собственно и удаляет элементы. Реализация идиомы:
#include #include #include void print (const std::vector& data) < for(const auto& n: data) < std::cout std::cout bool is_negative(int n) < return n < 0;>int main() < std::vectornumbers ; // применяем алгоритм remove_if() для удаления всех элементов, которые не соответствуют условию auto iter< std::remove_if(begin(numbers), end(numbers), is_negative) >; print(numbers); // 0 1 2 3 4 5 1 2 3 4 5 // удаляем все элементы, начиная с итератора first_to_erase numbers.erase(iter, end(numbers)); print(numbers); // 0 1 2 3 4 5 >
Здесь для примера удаляем из вектора все отрицательные числа. Для этого сначала вызываем функцию std::remove_if() :
auto iter< std::remove_if(begin(numbers), end(numbers), is_negative) >; print(numbers);
В качестве первого и второго параметров она принимает итераторы на начало и конец диапазона, из которого надо удалить числа. Здесь диапазон определяется итераторами на начало и конец вектора. В качестве третьего параметра передается условие. Условие должно представлять функцию, которая принимает некоторое значение и возвращает значение типа bool - true , если значение соответствует условию, и false - если не соответствует. В данном случае в качестве такого условия передаем функцию is_negative, которая вычисляет, является ли число отрицательным. То есть мы удаляем отрицательные числа.
Для вывода вектора на консоль применяется функция print. После выполнения remove_if на консоль будет выведено
0 1 2 3 4 5 1 2 3 4 5
В результате remove_if() просто перемещает все элементы, которые нужно сохранить (0 и положительные числа), в начало диапазона. При этом часть из этих чисел остается в конце вектора, но это не имеет значения, поскольку эта часть вектора будет удалена. А сама функция возвращает итератор iter, который указывает на первый удаляемый элемент. Далее удаляем все элементы, которые начинаются с этого итератора:
numbers.erase(iter, end(numbers)); print(numbers);
Теперь консольный вывод будет следующим:
0 1 2 3 4 5
std::erase_if()
Поскольку безопасное удаление из контейнеров представляет довольно часто встречаемую задачу, то начиная со стандарта C++20 в язык С++ были добавлены функции std::erase() и std::erase_if()
Функция std::erase() удаляет отдельное значение из контейнера (не применяется к std::set и std::map):
std::erase(Container, Value)
Функция std::erase_if() удаляет значения из контейнера, которые соответствуют условию:
std::erase_if(Container, Function)
Так, перепишем предыдущий пример с помощью функции std::erase_if :
#include #include void print (const std::vector& data) < for(const auto& n: data) < std::cout std::cout bool is_negative(int n) < return n < 0;>int main() < std::vectornumbers ; std::erase_if(numbers, is_negative); print(numbers); // 0 1 2 3 4 5 >
Операции с векторами в STL
Размер вектора можно узнать при помощи универсального метода size() , возвращающего для всех контейнеров в STL их размер. Также есть метод empty() , возвращающий логическое значение ( true , если вектор пустой).
Размер вектора можно изменить в любой момент, при помощи метода resize . У этого метода может быть один или два параметра. Вызов метода resize(n) изменяет размер вектора до n элементов (длина вектора может как уменьшится, так и увеличиться). Вызов метода resize(n, val) изменяет размер вектора до n элементов, и если при этом размер вектора увеличивается, то новые элементы получают значение, равное val.
Очень часто бывает полезно добавлять элементы в конец вектора по одному и удалять элементы из конца вектора по одному. Для добавления нового элемента, равного val в конец вектора используется метод push_back(val) . Для удаления последнего элемента вектора используется метод pop_back() — он не возвращает значения.
Добавление элемента в конец вектора осуществляется в среднем за O(1). Это реализовано за счет того, что память для хранения элементов вектора выделяется “с запасом”, то есть можно будет добавлять элементы по одному, пока не кончится запас памяти. Если запас памяти исчерпан, выделяется новая память, при этом "запас" размера вектора удваивается.
Очистить вектор можно при помощи метода clear() .
Вставка и удаление элементов в середину вектора
Для удаления и вставки элементов в середину вектора используются методы erase и insert . В качестве параметра им нужно передавать итератор, поэтому просто покажем на примере, как их использовать.
Итератор — специальный объект, указывающий на элемент вектора (или другой структуры данных). Итератор на элемент с индексом i можно получить при помощи выражения a.begin() + i . Кроме того, можно при помощи итератора a.end() “отсчитывать” элементы, начиная с конца. При этом a.end() будет итератором на элемент, следующий за последним, a.end() будет итератором на последний элемент, то есть то же самое, что a.begin() + a.size() - 1 , a.end() - 2 — второй элемент с конца и т.д.
Удаление элементов: метод erase
Метод erase позволяет удалять из середины вектора один или несколько элементов. Если вызвать метод erase с одним параметром–итератором, то будет удален соответствующий элемент из вектора, то есть для удаления элемента с индексом i из вектора a нужно вызвать метод следующим образом:
a.erase(a.begin() + i);
Методу erase передать два итератора на начало и конец удаляемого фрагмента, например:
a.erase(a.begin() + i, a.begin() + j);
В этом случае будут удалены элементы с индексами от i (включительно) до j не включительно, то есть элементы a[i] , a[i + 1] , . a[j - 1] . Всего будет удалено j - i элементов.
Методу erase можно передавать и итераторы, полученные относительно итератора end . Например, удалить из вектора три последних элемента можно так:
a.erase(a.end() - 3, a.end());
Подробней про его использование можно прочитать в документации.
Вставка элементов: метод insert
Метод insert позволяет вставлять в середину вектора новый элемент, или несколько равных элементов, или другой вектор, или фрагмент другого вектора. Этот метод также работает с итераторами и про его использование можно прочитать в документации.
Примеры использования метода insert :
Вставка одного элемента со значением val в позицию с индексом i :
a.insert(a.begin() + i, val);
Вставка нескольких равных (количеством count ) элементов со значением val в позицию с индексом i :
a.insert(a.begin() + i, count, val);
Вставка в вектор a в позицию с индексом i фрагмент вектора b с индексами от start включительно до finish не включительно:
a.insert(a.begin() + i, b.begin() + start, b.begin() + finish);
В качестве параметром могут использоваться произвольные итераторы. Рассмотрим несколько примеров:
Весь вектор b добавить в конец вектора a :
a.insert(a.end(), b.begin(), b.end());
Последние 5 элементов вектора b вставить в начало вектора a :
a.insert(a.begin(), b.end() - 5, b.end());
Поскольку вставка и удаление элементов требуют сдвига других элементов вектора, эти операции имеют линейную сложность, то есть выполняются за время, пропорциональное длине вектора.
Присваивание и сравнение векторов
Содержимое одного вектора можно целиком скопировать в другой вектор при помощи операции присваивания. При этом размер вектора A автоматически изменится и будет равен размеру вектора B . A = B .
Также векторы можно сравнивать на равенство и неравенство ( A == B , A != B ), и сравнивать их содержимое в лексикографическом порядке ( A < B , A B , A >= B ).
Типы данных
Строки Прежде чем пользоваться строковыми операциями и вообще иметь возможность описывать переменные типа string необходимо включить в заголовок программы описание:
Также во всех примерах предполагается, что в начале программы подключено пространство имен std:
using namespace std;
Описание строки полностью аналогично описанию любой другой переменной. Например:
string example_str;
- Присваивание
- Сравнение
- Ввод
- Запрос длины строки (size, length)
- Соединение (+)
- Удаление фрагмента (erase)
- Вставка фрагмента (insert)
- Копирование фрагмента (substr)
- Поиск фрагмента (find)
- Преобразование к числу (sscanf, sstream)
- Преобразование числа к строке (sprintf, sstream)
- Строка как массив символов
- Примечание(*)
Присваивание строк
Примеры с комментариями:
string example_str = "Do bats eat cats?"; // присваивание при описании example_str = ""; // присваивание пустой строки - // две кавычки рядом, без пробелов work_str = example_str; // присваивание между строками
Помимо этого возможно вот такое присваивание:
char a[50]; example_str = a;
Сравнение строк
Две строки равны друг другу, если у них одинаковые длины и символы на соответствующих местах полностью совпадают (то есть 1-й символ строки A равен 1-му символу строки B, 2-й символ строки A равен 2-му символу строки B и так далее)
Например строка "abc" равна строке "abc", но не равна строке "abcd".
Выяснение какая из строк больше выполняется посимвольно, аналогично алфавитному порядку русского языка. Если строка начинается с символа, чей код больше, что и сама строка больше. Если первые символы одинаковы, то сравниваются вторые символы по тому же правилу. Если и они одинаковы, сравниваются третьи и так далее. Если в процессе сравнения какая-то из строк закончилась, то она меньше другой.
Строку также можно сравнивать с пустой (обозначается двумя кавычками подряд, без пробелов).
while (example_str != "") < // какие-то команды >
Для ввода строк рекомендуется использовать функцию getline(). Данная функция читает строку целиком (с пробелами и прочими символами) до знака перевода строки.
getline(cin, example_str);
Длина строки
Функции size() или length() возвращают целое число - количество символов, которое сейчас находится в строке.
example_str = "Password"; int x = example_str.size(); // после этого фрагмента x = 8
example_str = ""; if (example_str.length() > 0) < // команды этого блока сейчас не выполнятся, // так как длина пустой строки равна 0 >;
Соединение строк
Операция + возвращает строку, получившуюся в результате соединения (дописывания одной строки после конца другой) одной или более строк. Строки соединяются в том порядке, как они указаны в операции.
example_str = "password"; article = "The " comment_str = "anyone can guess it." example_str = article + example_str + " is so simple, so " + comment_str; // example_str = "The password is so simple, so anyone can guess it."
Удаление фрагмента
Функция erase() удаляет указанный фрагмент строки (если это возможно). Первым параметром указывается начальный символ (с него начнется удаление), вторым - количество символов. Символы в строке нумеруются, начиная с 0.
example_str = "The star is so distant"; example_str.erase(3, 6); // example_str = "Theis so distant" // будет удалено слово star вместе с обоими пробелами
example_str = "The star is so distant"; example_str.erase(3, 80); // example_str = "The" // будет удалено столько символов, сколько возможно
Вставка фрагмента
С помощьью функции insert() можно добавить заданный фрагмент в любое место строки. Первым параметром функции является номер начальной позиции для фрагмента (нумерация начинается с 0), вторым - фрагмент. Функция изменяет исходную строку.
example_str = "123456"; example_str.insert(3, "+"); // теперь example_str = "123+456"
Копирование фрагмента
Функция substr() возвращает фрагмент строки (который тоже является строкой). Первым параметром указывается номер начального символа, вторым - количество. Символы нумеруются, начиная с 0. Функция не оказывает влияния на исходную строку.
example_str = "Do bats eat cats?"; new_str = example_str.substr(3, 5); // new_str = "bats " // будет скопировано слово "bats" вместе с последуюшим пробелом
example_str = "Do bats eat cats?"; new_str = example_str.substr(12, 100); // new_str = "cats?" // в строке нет 100 символов, поэтому будет скопировано сколько есть
Поиск фрагмента
С помощью функции find() можно определить, встречается ли данный фрагмент в строке. Функция возвращает специальное значение string::npos, если фрагмент не найден или номер первого (начиная слева) места, откуда начинается подобный фрагмент
example_str = "comandante@cia.dark.org"; x = example_str.find("z"); // в этом примере x равно string::npos, // так как в строке нет ни одной буквы z
example_str = "comandante@cia.dark.org"; x = example_str.find("a"); // в этом примере x равно 3, // символов "а" в строке несколько, но find // вернет номер только для первого слева
example_str = "comandante@cia.dark.org"; if (example_str.find("te") != string::npos) < // команды этого блока выполнятся, так как // в строке есть фрагмент "te" >
Преобразование к числу
1. Ввод/вывод в stringstream. Требуется создать специальный поток ввода/вывода, который будет вводить или выводить данные в некоторый буффер в памяти. При этом операции будут сходны со стандартным вводом/выводом.
#include
2. Функция sscanf() (scan from string as fromatted). Данная функция также из обычного C (не C++) поэтому "умеет" работать только с символьными массивами. В грубом приближении у функции 3 параметра: символьный массив, строка формата и переменная (или переменные), куда следует поместить результаты преобразования.
#include
Преобразование числа к строке
1. Ввод/вывод в stringstream. Требуется создать специальный поток ввода/вывода, который будет вводить или выводить данные в некоторый буффер в памяти. При этом операции будут сходны со стандартным вводом/выводом.
#include
2. sprintf() (print formatted to string). Эта функция также является функцией из стандартного C, и тоже работает только с массивами из char). Параметры (вкратце): символьный массив, куда будет выведен результат, строка формата, данные.
Подробнее про строку формата см. например, здесь.
#include
Строка как массив символов
Строку можно рассматривать как массив символов и применять к ней методы работы, как с массивом.