Ответ 1
Я понял.
size_t found = text.find('.');
text.erase(found, 1);
У меня есть строка, и я хочу удалить из нее все помехи. Как мне это сделать? Я провел некоторое исследование и обнаружил, что люди используют функцию ispunct() (я пробовал это), но я не могу заставить ее работать в моем коде. У кого-нибудь есть идеи?
#include <string>
int main() {
string text = "this. is my string. it here."
if (ispunct(text))
text.erase();
return 0;
}
Я понял.
size_t found = text.find('.');
text.erase(found, 1);
Использование алгоритма remove_copy_if
: -
string text,result;
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(result), //Store output
std::ptr_fun<int, int>(&std::ispunct)
);
У POW уже есть хороший ответ, если вам нужен результат в виде новой строки. Этот ответ - как с этим справиться, если вы хотите обновить на месте.
Первая часть рецепта - это std::remove_if
, которая может эффективно удалить пунктуацию, упаковывая все знаки препинания по мере необходимости.
std::remove_if (text.begin (), text.end (), ispunct)
К сожалению, std::remove_if
не сжимает строку до нового размера. Не может, потому что не имеет доступа к самому контейнеру. Поэтому после упакованного результата в строке остались ненужные символы.
Для этого std::remove_if
возвращает итератор, который указывает часть строки, которая все еще нужна. Это можно использовать с методом erase
строк, что приводит к следующей идиоме...
text.erase (std::remove_if (text.begin (), text.end (), ispunct), text.end ());
Я называю это идиомой, потому что это распространенная техника, которая работает во многих ситуациях. Другие типы, кроме string
предоставляют подходящие методы erase
, и std::remove
(и, возможно, некоторые другие функции библиотеки алгоритмов, которые я на данный момент забыл) используют этот подход, чтобы закрыть пробелы для удаляемых элементов, но оставляя изменение размера контейнера для вызывающий абонент.
#include <string>
#include <iostream>
#include <cctype>
int main() {
std::string text = "this. is my string. it here.";
for (int i = 0, len = text.size(); i < len; i++)
{
if (ispunct(text[i]))
{
text.erase(i--, 1);
len = text.size();
}
}
std::cout << text;
return 0;
}
Выход
this is my string its here
При удалении символа изменяется размер строки. Он должен обновляться при каждом удалении. И вы удалили текущий символ, поэтому следующий символ станет текущим символом. Если вы не уменьшаете счетчик циклов, символ рядом с символом пунктуации не будет проверяться.
ispunct
принимает значение char
не строку.
вы можете сделать как
for (auto c : string)
if (ispunct(c)) text.erase(text.find_first_of(c));
Это будет работать, но это медленный алгоритм.
Проблема заключается в том, что ispunct() принимает один аргумент как символ, в то время как вы пытаетесь отправить строку. Вы должны перебирать элементы строки и стирать каждый символ, если это пунктуация, как здесь:
for(size_t i = 0; i<text.length(); ++i)
if(ispunct(text[i]))
text.erase(i--, 1);
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string str = "this. is my string. it here.";
transform(str.begin(), str.end(), str.begin(), [](char ch)
{
if( ispunct(ch) )
return '\0';
return ch;
});
}
Довольно хороший ответ от Steve314. Я хотел бы добавить небольшое изменение:
text.erase (std::remove_if (text.begin (), text.end (), ::ispunct), text.end ());
Добавление :: before функция ispunct заботится о перегрузке.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;//string is defined here.
cout << "Please enter a string with punctuation's: " << endl;//Asking for users input
getline(cin, s);//reads in a single string one line at a time
/* ERROR Check: The loop didn't run at first because a semi-colon was placed at the end
of the statement. Remember not to add it for loops. */
for(auto &c : s) //loop checks every character
{
if (ispunct(c)) //to see if its a punctuation
{
c=' '; //if so it replaces it with a blank space.(delete)
}
}
cout << s << endl;
system("pause");
return 0;
}
Другим способом, который вы могли бы сделать это, было бы следующее:
#include <ctype.h> //needed for ispunct()
string onlyLetters(string str){
string retStr = "";
for(int i = 0; i < str.length(); i++){
if(!ispunct(str[i])){
retStr += str[i];
}
}
return retStr;
Это приводит к созданию новой строки вместо фактического стирания символов из старой строки, но немного легче обернуть голову, чем использовать некоторые из более сложных встроенных функций.
Попробуйте использовать этот, он удалит всю пунктуацию в строке в текстовом файле oky. str.erase(remove_if (str.begin(), str.end(),:: ispunct), str.end());
ответьте, если полезно
Я пытался применить ответ @Steve314, но не смог заставить его работать, пока не наткнулся на эту заметку здесь на cppreference.com:
Заметки
Как и все другие функции из
<cctype>
, поведениеstd::ispunct
не определено, если значение аргумента не может быть представлено какunsigned char
и равно EOF. Чтобы безопасно использовать эти функции с простымchar
(илиsigned char
), аргумент должен быть сначала преобразован вunsigned char
.
Изучая приведенный пример, я могу заставить его работать так:
#include <string>
#include <iostream>
#include <cctype>
#include <algorithm>
int main()
{
std::string text = "this. is my string. it here.";
std::string result;
text.erase(std::remove_if(text.begin(),
text.end(),
[](unsigned char c) { return std::ispunct(c); }),
text.end());
std::cout << text << std::endl;
}