ЕСЛИ строка может содержать несколько ненужных элементов, например, @, #, $,%.
Как их найти и удалить?
Я знаю, что для этого требуется итерация цикла, но я не знаю, как представлять sth, например @, #, $,%.
Если вы можете привести пример кода, тогда я буду очень признателен.
Обычным стандартным подходом C ++ будет идиома стирания / удаления :
#include <string>
#include <algorithm>
#include <iostream>
struct OneOf {
std::string chars;
OneOf(const std::string& s) : chars(s) {}
bool operator()(char c) const {
return chars.find_first_of(c) != std::string::npos;
}
};
int main()
{
std::string s = "string with @, #, $, %";
s.erase(remove_if(s.begin(), s.end(), OneOf("@#$%")), s.end());
std::cout << s << '\n';
}
, и да, boost предлагает несколько изящных способов сделать это короче, например, используя boost :: erase_all_regex
#include <string>
#include <iostream>
#include <boost/algorithm/string/regex.hpp>
int main()
{
std::string s = "string with @, #, $, %";
erase_all_regex(s, boost::regex("[@#$%]"));
std::cout << s << '\n';
}
Если хотите пофантазировать, есть Boost.Regex , в противном случае вы можете использовать функцию STL replace в сочетании с функцией strchr .. [
И если вам по какой-то причине придется делать это самостоятельно в стиле C, то сработает что-то вроде этого:
char* oldstr = ... something something dark side ...
int oldstrlen = strlen(oldstr)+1;
char* newstr = new char[oldstrlen]; // allocate memory for the new nicer string
char* p = newstr; // get a pointer to the beginning of the new string
for ( int i=0; i<oldstrlen; i++ ) // iterate over the original string
if (oldstr[i] != '@' && oldstr[i] != '#' && etc....) // check that the current character is not a bad one
*p++ = oldstr[i]; // append it to the new string
*p = 0; // dont forget the null-termination
Думаю, для этого я бы использовал std::remove_copy_if
:
#include <string>
#include <algorithm>
#include <iostream>
struct bad_char {
bool operator()(char ch) {
return ch == '@' || ch == '#' || ch == '$' || ch == '%';
}
};
int main() {
std::string in("This@is#a$string%with@extra#stuff$to%ignore");
std::string out;
std::remove_copy_if(in.begin(), in.end(), std::back_inserter(out), bad_char());
std::cout << out << "\n";
return 0;
}
Результат:
Thisisastringwithextrastufftoignore
Поскольку данные, содержащие эти нежелательные символы, обычно поступают из какого-то файла, стоит также подумать о том, чтобы избавиться от них по мере чтения данных из файла, вместо того чтобы считывать нежелательные данные в строку и затем отфильтровывать их. Для этого можно создать фасет, который классифицирует ненужные символы как пробелы:
struct filter: std::ctype<char>
{
filter(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::mask());
rc['@'] = std::ctype_base::space;
rc['#'] = std::ctype_base::space;
rc['$'] = std::ctype_base::space;
rc['%'] = std::ctype_base::space;
return &rc[0];
}
};
Чтобы использовать это, вы нагружаете входной поток локалью, использующей этот фасет, а затем читаете нормально. В данный момент я буду использовать istringstream
, хотя обычно вы используете что-то вроде istream
или ifstream
:
int main() {
std::istringstream in("This@is#a$string%with@extra#stuff$to%ignore");
in.imbue(std::locale(std::locale(), new filter));
std::copy(std::istream_iterator<char>(in),
std::istream_iterator<char>(),
std::ostream_iterator<char>(std::cout));
return 0;
}
используйте оператор характеризации, то есть a
будет 'a'
. вы не сказали, используете ли вы строки C ++ (в этом случае вы можете использовать методы поиска и замены) или строки C, и в этом случае вы бы использовали что-то вроде этого (это отнюдь не лучший способ, но это простой способ):
void RemoveChar(char* szString, char c)
{
while(*szString != '\0')
{
if(*szString == c)
memcpy(szString,szString+1,strlen(szString+1)+1);
szString++;
}
}
Общий алгоритм:
В зависимости от используемой строковой библиотеки существуют функции / методы, которые реализуют один или несколько из вышеперечисленных шагов, например strchr () или find () для определения того, находится ли символ в строке.
Это C или C ++? (Вы пометили его обоими способами.)
В чистом C вам в значительной степени нужно перебирать символ за символом и удалять ненужные. Например:
char *buf;
int len = strlen(buf);
int i, j;
for (i = 0; i < len; i++)
{
if (buf[i] == '@' || buf[i] == '#' || buf[i] == '$' /* etc */)
{
for (j = i; j < len; j++)
{
buf[j] = buf[j+1];
}
i --;
}
}
Это не очень эффективно - он проверяет каждый символ по очереди и перемешивает их все, если один из них вам не нужен. После этого вам нужно уменьшить индекс, чтобы убедиться, что вы проверяете новый следующий символ.
Вы можете использовать цикл и вызвать find_last_of
( http://www.cplusplus.com/reference/string/string/find_last_of/ ) несколько раз, чтобы найти последний символ, который вы хотите заменить, замените его пустым, а затем продолжите работу в обратном направлении по строке.
Можно было бы сделать что-то вроде этого:
bool is_bad(char c)
{
if( c == '@' || c == '#' || c == '$' || c == '%' )
return true;
else
return false;
}
int main(int argc, char **argv)
{
string str = "a #test #@string";
str.erase(std::remove_if(str.begin(), str.end(), is_bad), str.end() );
}
Если ваш компилятор поддерживает лямбда-выражения (или если вы можете использовать ускорение), его можно сделать еще короче. Пример использования boost :: lambda:
string str = "a #test #@string";
str.erase(std::remove_if(str.begin(), str.end(), (_1 == '@' || _1 == '#' || _1 == '$' || _1 == '%')), str.end() );
(ура две строки!)
Символ представлен в C / C ++ одинарными кавычками, например '@', '#' и т. д. (за исключением некоторых, которые нужно экранировать).
Для поиска символа в строке используйте strchr (). Вот ссылка на образец кода: