web-dev-qa-db-ja.com

C ++で文字列からすべての非英数字を取り除く方法は?

私はソフトウェアを書いており、libcurlを使用してWebページから取得したデータを処理する必要があります。データを取得すると、何らかの理由で余分な改行が含まれています。文字、数字、スペースのみを許可する方法を理解する必要があります。そして、改行を含むその他すべてを削除します。これを行う簡単な方法はありますか?ありがとう。

23

charを取り、その文字を削除する場合はtrueを返し、保持する場合はfalseを返す関数を記述します。

bool my_predicate(char c);

次に、std::remove_ifアルゴリズムを使用して、不要な文字を文字列から削除します。

std::string s = "my data";
s.erase(std::remove_if(s.begin(), s.end(), my_predicate), s.end());

要件によっては、独自の述語を作成する代わりに、std::isalnumなどの標準ライブラリの述語のいずれかを使用できる場合があります(英数字とスペースを一致させる必要があると述べたため、これは正確にできない場合があります)必要なものに合わせてください)。

標準ライブラリstd::isalnum関数を使用する場合は、C標準ライブラリヘッダーstd::isalnum(使用する関数)の<cctype>関数を明確にするキャストが必要です。 )およびC++標準ライブラリヘッダーのstd::isalnum<locale>(ロケール固有の文字列処理を実行する場合を除いて、これは使用するものではありません):

s.erase(std::remove_if(s.begin(), s.end(), (int(*)(int))std::isalnum), s.end());

これは、任意のシーケンスコンテナ(std::stringstd::vectorstd::dequeを含む)でも同様に機能します。このイディオムは一般に「消去/削除」イディオムと呼ばれます。 std::remove_ifアルゴリズムは、通常の配列でも機能します。 std::remove_ifは、シーケンスを1回だけ通過するため、時間の複雑さが線形になります。

44
James McNellis

以前のstd::isalnumの使用は、_nary引数を渡さないとstd::ptr_funでコンパイルできません。したがって、ラムダ関数を使用したこのソリューションは正しい答えをカプセル化する必要があります。

s.erase(std::remove_if(s.begin(), s.end(), 
[]( auto const& c ) -> bool { return !std::isalnum(c); } ), s.end());
10
Dado

eraseを使用している場合は、常にループして、stringの英数字以外のすべての文字だけをループできます。

#include <cctype>

size_t i = 0;
size_t len = str.length();
while(i < len){
    if (!isalnum(str[i]) || str[i] == ' '){
        str.erase(i,1);
        len--;
    }else
        i++;
}

標準Libの優れた人なら、ループなしでこれを実行できるでしょう。

charバッファのみを使用している場合はループすることができ、文字が英数字ではない場合は、後ろにあるすべての文字を1つ後ろにシフトします(問題の文字を上書きします)。

#include <cctype>

size_t buflen = something;
for (size_t i = 0; i < buflen; ++i)
    if (!isalnum(buf[i]) || buf[i] != ' ')
        memcpy(buf[i], buf[i + 1], --buflen - i);
4
Seth Carnegie

remove_copy_if 標準アルゴリズムは、ケースに非常に適しています。

#include <cctype>
#include <string>
#include <functional>

std::string s = "Hello World!";
s.erase(std::remove_if(s.begin(), s.end(),
    std::not1(std::ptr_fun(std::isalnum)), s.end()), s.end());
std::cout << s << std::endl;

結果:

"HelloWorld"

isalnumを使用して各文字が英数字であるかどうかを判別し、次にptr_funを使用して関数をnot1に渡します。これにより、戻り値ではなく、英数字のみが残ります。欲しいです。

2
TankorSmash

この方法で削除消去アルゴリズムを使用できます-

// Removes all punctuation       
s.erase( std::remove_if(s.begin(), s.end(), &ispunct), s.end());
1
akritaag

James McNellisのコードをもう少し拡張するだけです。彼の機能は、非文字ではなく文字を削除することです。

文字列からnon-alnum文字を削除します。 (alnum =アルファベット順または数値)

  • 関数を宣言します(渡されたcharがalnumでない場合、isalnumは0を返します)

    bool isNotAlnum(char c) {
        return isalnum(c) == 0;
    }
    
  • そしてこれを書いてください

    s.erase(remove_if(s.begin(), s.end(), isNotAlnum), s.end());
    

次に、あなたの文字列はalnum文字のみです。

1
Ali Eren Çelik

上記の解決策

s.erase( std::remove_if(s.begin(), s.end(), &std::ispunct), s.end());

は非常にいいですが、残念ながらVisual Studio(デバッグモード)で 'Ñ'のような文字を処理することはできません。次の行が原因です。

_ASSERTE((unsigned)(c + 1) <= 256)

isctype.c内

だから、私はこのようなものをお勧めします:

inline int my_ispunct( int ch )
{
    return std::ispunct(unsigned char(ch));
}
...
s.erase( std::remove_if(s.begin(), s.end(), &my_ispunct), s.end());
0
Andres Hurtis

以下のコードは、与えられた文字列sに対してうまく機能するはずです。 <algorithm>および<locale>ライブラリを利用しています。

std::string s("He!!llo  Wo,@rld! 12 453");
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return !std::isalnum(c); }), s.end());
0
Dhruv Kakadiya

次は私のために働きます。

str.erase(std::remove_if(str.begin(), str.end(), &ispunct), str.end());
str.erase(std::remove_if(str.begin(), str.end(), &isspace), str.end());
0
Pabitra Dash
void remove_spaces(string data)
{ int i=0,j=0;
    while(i<data.length())
    {
        if (isalpha(data[i]))
        {
        data[i]=data[i];
        i++;
        }
        else
            {
            data.erase(i,1);}
    }
    cout<<data;
}
0
Imran Saeed