2016-12-07 9 views
0

単純な方法で英数字以外の文字を避けて、単語ごとにテキストを読みたい。 空白と '\ n'を含むテキストから '進化'した後、 '、'、 '。'がある場合に問題を解決する必要があります。例えば。 最初のケースは、デリミタ ''付きのgetlineを使うだけで簡単に解決できました。 getlineに複数の区切り文字を使用する方法や、ある種の正規表現(たとえば'.'|' '|','|'\n')を使用する方法があるかどうかは疑問でした。getline関数用の複数のデリミタ

私が知る限り、getlineは、 '\ n'またはdelimiter文字に達するまで、入力ストリームから文字を読み込む方法で動作します。私の最初の推測では、複数の区切り文字を提供するのは非常に簡単ですが、そうではないことがわかりました。

編集:説明と同様です。任意のCスタイル(strtokは、私の意見では非常に醜い)やアルゴリズムのタイプのソリューションは、私が探しているものではありません。その問題を解決する簡単なアルゴリズムを思いついて実装するのはかなり簡単です。私は完全に誤解しない限り、何とか1つ以上の区切り文字を受け入れることができるはずだから、より洗練された解決法、あるいは少なくともなぜ私たちがgetline関数で扱うことができないのかについての説明を探しています。

+0

@GabeNonesええと、私たちはCとC++の両方にタグをつけて、このCの疑問を解決することはできません。私たちはC++を見つけなければなりません。 –

+0

@BaummitAugen:C++のDupeを見つけることは大丈夫ですが、あなたがそれに対してクローズしたものは、特に優れたDupe(少なくともIMO)ではありません。 1つの答えでは、この問題はまったく解決されません(ストリングの分割のみを扱い、ここで必要なストリームからの読み込みは扱いません)。もう片方はうまく動作しますが、偶然によって並べ替えられます(これは '\ n'がデリミタでなければならないが、それを望んでいない他の人にとってはうまくいきません)。 –

+0

@JerryCoffin質問は同じように思えます。他の質問にもっと良い回答が必要な場合は、まだ回答を追加することはできますが、それは閉じられません。 –

答えて

1

良いニュースと悪いニュースがあります。良いニュースはあなたがこれを行うことができるということです。

悪い知らせは、それを行うことはかなりラウンドアバウトであり、一部の人々はそれがまったく醜くて厄介なことに気付いています。それを行うには

は、次の2つの事実を観察することによって開始:

  1. 通常の文字列の抽出は「言葉」を区切るために空白を使用しています。
  2. 空白を構成するものは、ストリームのロケールで定義されています。一緒にそれらを置く

が、答えは(遠回りの場合)かなり明白になっ:複数の区切り文字を定義するために、私たちは私たちが区切り文字として扱われるべきである何文字を指定することができますロケール(すなわち、ホワイトスペース)を定義します。

struct word_reader : std::ctype<char> { 
    word_reader(std::string const &delims) : std::ctype<char>(get_table(delims)) {} 
    static std::ctype_base::mask const* get_table(std::string const &delims) { 
     static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask()); 

     for (char ch : delims) 
      rc[ch] = std::ctype_base::space; 
     return &rc[0]; 
    } 
}; 

その後、我々は、我々は、区切り文字として使用する文字を渡し、(そのCTYPEファセットを持つだけでなく、ロケール)そのロケールを使用するようにストリームを伝える必要があり、その後、ストリームから単語を抽出します。

int main() { 
    std::istringstream in("word1, word2. word3,word4"); 

    // create a ctype facet specifying delimiters, and tell stream to use it: 
    in.imbue(std::locale(std::locale(), new word_reader(" ,.\n"))); 
    std::string word; 

    // read words from the stream. Note we just use `>>`, not `std::getline`: 
    while (in >> word) 
     std::cout << word << "\n"; 
} 

結果はあなたが望むものです:私たちが言った句読点を使わずに各単語を抽出することは、 "空白"でした。

word1 
word2 
word3 
word4 
+0

まあ、それは確かに固い解決策ですが、あなたはかなり些細なことを言及し、それにいくつかの「不正な」エッセンスを持っています(必要な区切り文字を空白で置き換えます)。 デリミタの世界が空白と\ nに絞られている場合に 'getline'が実行するように、Nがファイルの長さと同じようにN個の演算を行うというより洗練された解があるのだろうかと思いました。 – GoldenSpecOps

+0

@GoldenSpecOps:私たちは何も置き換えていません。ストリームは単語の終わりを探しています。それは文字を取得します。ロケールを尋ねる: "これは空白ですか?"ファイルの終わりに達するまで、単語に文字を追加し続けるか、ロケールに「はい、空白です」と表示されます。次に、ロケールが次の文字が空白であることを継続している限り、前方にスキップします。泡立て、リンス、繰り返します。 –

+0

getlineとの主な違いは、 'a \ n \ n \ nz'のようなものがある場合、' getline'は 'a'、空行、空行' z'を読み込みますが、それはちょうど 'a'、' z'と同じです。 –

関連する問題