анализ строки

ЕСЛИ строка может содержать несколько ненужных элементов, например, @, #, $,%.

Как их найти и удалить?

Я знаю, что для этого требуется итерация цикла, но я не знаю, как представлять sth, например @, #, $,%.

Если вы можете привести пример кода, тогда я буду очень признателен.

6
задан James 20 August 2010 в 13:21
поделиться

10 ответов

Обычным стандартным подходом 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';
}
13
ответ дан 8 December 2019 в 03:38
поделиться

Если хотите пофантазировать, есть Boost.Regex , в противном случае вы можете использовать функцию STL replace в сочетании с функцией strchr .. [

3
ответ дан 8 December 2019 в 03:38
поделиться

И если вам по какой-то причине придется делать это самостоятельно в стиле 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
3
ответ дан 8 December 2019 в 03:38
поделиться

Думаю, для этого я бы использовал 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;
}
3
ответ дан 8 December 2019 в 03:38
поделиться

используйте оператор характеризации, то есть 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++;
    }
}
1
ответ дан 8 December 2019 в 03:38
поделиться

Общий алгоритм:

  1. Создайте строку, содержащую символы, которые вы хотите очистить: «@ # $%»
  2. Посимвольно перебирать строку темы.
  3. Выполните поиск, если каждый символ найден в наборе для очистки.
  4. Если символ совпадает, отбросьте его.
  5. Если символ не соответствует, добавьте его в строку результата.

В зависимости от используемой строковой библиотеки существуют функции / методы, которые реализуют один или несколько из вышеперечисленных шагов, например strchr () или find () для определения того, находится ли символ в строке.

2
ответ дан 8 December 2019 в 03:38
поделиться

Это 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 --;
    }
}

Это не очень эффективно - он проверяет каждый символ по очереди и перемешивает их все, если один из них вам не нужен. После этого вам нужно уменьшить индекс, чтобы убедиться, что вы проверяете новый следующий символ.

2
ответ дан 8 December 2019 в 03:38
поделиться

Вы можете использовать цикл и вызвать find_last_of ( http://www.cplusplus.com/reference/string/string/find_last_of/ ) несколько раз, чтобы найти последний символ, который вы хотите заменить, замените его пустым, а затем продолжите работу в обратном направлении по строке.

1
ответ дан 8 December 2019 в 03:38
поделиться

Можно было бы сделать что-то вроде этого:

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() );

(ура две строки!)

1
ответ дан 8 December 2019 в 03:38
поделиться

Символ представлен в C / C ++ одинарными кавычками, например '@', '#' и т. д. (за исключением некоторых, которые нужно экранировать).

Для поиска символа в строке используйте strchr (). Вот ссылка на образец кода:

http://www.cplusplus.com/reference/clibrary/cstring/strchr/

-1
ответ дан 8 December 2019 в 03:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: