Метод pop_back() из std::string
Последний символ строки на C++ проще всего удаляется методом pop_back()
, представленным в C++11. Причем символ удаляется за постоянное время:
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
str.pop_back();
std::cout << str << std::endl; // Выводится: «Hello, World»
return 0;
}
pop_back()
— эффективный и простой метод. Но удаленный символ им не возвращается и, если строка пуста, выдается исключение.
Метод resize()
Это метод с увеличением и уменьшением размера строки:
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
str.resize(str.length() - 1);
std::cout << str << std::endl; // Выводится: «Hello, World»
return 0;
}
Метод resize()
универсален: им удаляются символы из конца строки, при этом указывается новый размер.
Метод erase()
Этим методом предоставляется больше контроля за тем, какую часть строки удалить. Вот как удаляется последний символ:
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
str.erase(str.length() - 1);
std::cout << str << std::endl; // Выводится: «Hello, World»
return 0;
}
При помощи erase()
удаляется конкретная подстрока или диапазон символов.
Метод substr()
Этим методом создается новая строка без последнего символа:
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
str = str.substr(0, str.length() - 1);
std::cout << str << std::endl; // Выводится: «Hello, World»
return 0;
}
Пригождается substr()
и в ситуациях, когда нужно сохранить исходную строку.
Обработка пустых строк
При удалении последнего символа важно учесть случай пустых строк, избежав тем самым неопределенного поведения:
#include <iostream>
#include <string>
void removeLastChar(std::string& str) {
if (!str.empty()) {
str.pop_back();
}
}
int main() {
std::string str1 = "Hello";
std::string str2 = "";
removeLastChar(str1);
removeLastChar(str2);
std::cout << "str1: " << str1 << std::endl; // Выводится: «Hell»
std::cout << "str2: " << str2 << std::endl; // Выводится: пустая строка
return 0;
}
Если строка не пуста, этой функцией безопасно удаляется последний символ, чем предотвращаются возможные ошибки времени выполнения.
Производительность
При работе с большими строками или частыми операциями важна производительность. Сравним эффективность методов:
#include <iostream>
#include <string>
#include <chrono>
const int ITERATIONS = 1000000;
void benchmarkPopBack(std::string str) {
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; ++i) {
str.pop_back();
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "pop_back() time: " << diff.count() << " seconds" << std::endl;
}
void benchmarkResize(std::string str) {
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; ++i) {
str.resize(str.length() - 1);
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "resize() time: " << diff.count() << " seconds" << std::endl;
}
void benchmarkErase(std::string str) {
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < ITERATIONS; ++i) {
str.erase(str.length() - 1);
}
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = end - start;
std::cout << "erase() time: " << diff.count() << " seconds" << std::endl;
}
int main() {
std::string longString(ITERATIONS, 'a');
benchmarkPopBack(longString);
benchmarkResize(longString);
benchmarkErase(longString);
return 0;
}
По этому тесту производительности, быстрейшим обычно получается pop_back()
, за которым с небольшим отставанием располагается resize()
, чуть медленнее — erase()
.
Реальный сценарий: синтаксический анализатор CSV
Реализуем простой CSV-парсер, которым из каждой строки удаляются конечные запятые:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
class CSVParser {
private:
std::vector<std::vector<std::string>> data;
void removeTrailingComma(std::string& str) {
if (!str.empty() && str.back() == ',') {
str.pop_back();
}
}
public:
void parse(const std::string& input) {
std::istringstream stream(input);
std::string line;
while (std::getline(stream, line)) {
removeTrailingComma(line);
std::vector<std::string> row;
std::istringstream lineStream(line);
std::string cell;
while (std::getline(lineStream, cell, ',')) {
row.push_back(cell);
}
data.push_back(row);
}
}
void print() const {
for (const auto& row : data) {
for (const auto& cell : row) {
std::cout << cell << "\t";
}
std::cout << std::endl;
}
}
};
int main() {
CSVParser parser;
std::string csvData =
"Name,Age,City,\n"
"John,30,New York,\n"
"Alice,25,London,\n"
"Bob,35,Paris,";
parser.parse(csvData);
parser.print();
return 0;
}
Это практический пример удаления последнего символа строки методом pop_back()
.
«Юникод» и многобайтовые символы
При работе с «Юникодом» или многобайтовыми символами удалить последний символ сложнее. Методом pop_back()
удаляется последний байт, который в многобайтовой кодировке может оказаться не последним символом.
Для строк «Юникода» используется соответствующая библиотека, такая как International Components for Unicode, или функции с поддержкой UTF-8:
#include <iostream>
#include <string>
#include <codecvt>
#include <locale>
std::wstring removeLastUnicodeChar(const std::wstring& str) {
if (str.empty()) {
return str;
}
return str.substr(0, str.length() - 1);
}
int main() {
std::wstring str = L"Hello, 世界!";
str = removeLastUnicodeChar(str);
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::string utf8Str = converter.to_bytes(str);
std::cout << utf8Str << std::endl; // Выводится: «Hello, 世界»
return 0;
}
В этом примере символы «Юникода» корректно обрабатываются строками в многобайтовой кодировке std::wstring
.
Функциональный подход с алгоритмами
Для более функционального стиля программирования используются алгоритмы из стандартной библиотеки C++:
#include <iostream>
#include <string>
#include <algorithm>
std::string removeLastChar(std::string str) {
return std::string(str.begin(), str.end() - (str.empty() ? 0 : 1));
}
int main() {
std::string str = "Hello, World!";
str = removeLastChar(str);
std::cout << str << std::endl; // Выводится: «Hello, World»
return 0;
}
При таком подходе новая строка создается без изменения исходной, в некоторых сценариях пригодится.
Типичные ошибки и как их избежать
- Не проверяется наличие пустых строк. До удаления последнего символа всегда проверяйте, не пуста ли строка.
- Предполагается, что символы однобайтовые. Будьте осторожны при работе с «Юникодом» или многобайтовыми кодировками.
- Изменение строковых литералов. Не забывайте, что строковые литералы неизменяемы, при изменении строк всегда работайте с объектами
std::string
. - Упускаются из виду строковые представления. Чтобы повысить производительность, для строковых операций без изменения строк в версии C++17 или новее используйте
std::string_view
. - Лишнее копирование. Во избежание ненужных копий строк — особенно больших строк — по возможности используйте ссылки.
Заключение
Удаление последнего символа строки на C++ — распространенная операция с разными вариантами реализации. В простых сценариях pop_back()
обычно эффективнее, в сложных методы resize()
, erase()
и substr()
оказываются гибче.
При работе со строками на C++ всегда учитывайте конкретные требования задачи. Имеется «Юникод»? Нужно ли сохранить исходную строку? Важна ли производительность?
Ответив на эти вопросы, вы выберете оптимальный метод удаления последнего символа строки.
Читайте также:
- Чем отличается C++ от C#?
- Насколько С++ быстрее Python
- 4 совета по работе с потоками и мьютексами в C++
Читайте нас в Telegram, VK и Дзен
Перевод статьи ryan: C++ Remove Last Character from String: Methods and Applications