web-dev-qa-db-ja.com

C ++文字列から句読点を削除する

文字列を取得し、それから句読点をすべて削除したい。それ、どうやったら出来るの?私はいくつかの調査を行い、人々がispunct()関数を使用していることを発見しました(私はそれを試しました)が、それを私のコードで機能させることができないようです。誰かアイデアはありますか?

#include <string>

int main() {

string text = "this. is my string. it's here."

if (ispunct(text))
text.erase();

return 0;
}
11
NewFile

アルゴリズムの使用 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)  
                       );
23
P0W

新しい文字列として結果が必要な場合、POWにはすでに適切な回答があります。この答えは、インプレース更新が必要な場合の処理​​方法です。

レシピの最初の部分はstd::remove_ifは、句読点を効率的に削除し、句読点以外のすべてをそのままパッキングします。

std::remove_if (text.begin (), text.end (), ispunct)

残念ながら、std::remove_ifは、文字列を新しいサイズに縮小しません。コンテナ自体にアクセスできないため、できません。したがって、パックされた結果の後に文字列にジャンク文字が残っています。

これを処理するには、std::remove_ifは、まだ必要な文字列の部分を示すイテレータを返します。これは、strings eraseメソッドで使用でき、次のイディオムにつながります...

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

これは多くの状況で機能する一般的な手法であるため、これをイディオムと呼びます。 string以外のタイプは、適切なeraseメソッドを提供し、std::remove(そしておそらく私が今のところ忘れてしまった他のいくつかのアルゴリズムライブラリ関数)は、削除するアイテムのギャップを埋めるこのアプローチを採用しますが、コンテナーのサイズ変更は呼び出し元に任せます。

16
Steve314

ispunctは文字列ではなくchar値を取ります。

あなたは好きにできます

for (auto c : string)
     if (ispunct(c)) text.erase(text.find_first_of(c));

これは機能しますが、遅いアルゴリズムです。

4
CS Pei
#include <string>
#include <iostream>
#include <cctype>

int main() {

    std::string text = "this. is my string. it's 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

文字を削除すると、文字列のサイズが変わります。削除が発生するたびに更新する必要があります。そして、現在の文字を削除したので、次の文字が現在の文字になります。ループカウンターをデクリメントしない場合、句読文字の次の文字はチェックされません。

4
thefourtheye
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    string str = "this. is my string. it's here.";

    transform(str.begin(), str.end(), str.begin(), [](char ch)
    {
        if( ispunct(ch) )
            return '\0';
        return ch;
    });
}
1
user1233963

ここでの問題は、ispunct()が文字列を送信しようとしているときに、1つの引数が文字であることです。次のような句読点の場合は、文字列の要素をループして、各文字を削除する必要があります。

for(size_t i = 0; i<text.length(); ++i)
  if(ispunct(text[i]))
    text.erase(i--, 1);
1
pippin1289

Steve314によるかなり良い答え。小さな変更を追加したいと思います。

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

関数ispunctの前に::を追加すると、オーバーロードが処理されます。

1
Siddharth Singh

これを使用してみてください。テキストファイルの文字列の句読点がすべて削除されます。 str.erase(remove_if(str.begin()、str.end()、:: ispunct)、str.end());

参考になれば返信してください

0
Loshiye Sindiyo

これを行う別の方法は、次のとおりです。

#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;

これは、実際には古い文字列から文字を消去するのではなく、新しい文字列を作成することになりますが、複雑な組み込み関数のいくつかを使用するよりも頭を一周する方が簡単です。

0
willard5991

私は@ Steve314の回答を適用しようとしましたが、このメモに出会うまでそれを機能させることができませんでした ここ cppreference.com:

注意事項

<cctype>の他のすべての関数と同様に、引数の値がstd::ispunctとして表現できないか、EOFと等しくない場合のunsigned charの動作は未定義です。これらの関数をプレーンなchars(またはsigned chars)で安全に使用するには、まず引数をunsigned charに変換する必要があります。

それが提供する例を研究することにより、私はそれを次のように機能させることができます:

#include <string>
#include <iostream>
#include <cctype>
#include <algorithm>

int main()
{
    std::string text = "this. is my string. it's 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;
}
0
Xucong
 #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;
   }
0
prsmith