web-dev-qa-db-ja.com

cinの区切り文字の変更(c ++)

ファイルストリームから読み取るように「cin」をリダイレクトしましたcin.rdbug(inF.rdbug())抽出演算子を使用すると、空白文字に達するまで読み取ります。

別の区切り文字を使用することはできますか? cplusplus.comのapiを調べましたが、何も見つかりませんでした。

42
yotamoo

cin または他の std::istream のワード間区切り文字を変更することは、 std::ios_base::imbueを使用して可能です。 カスタムを追加するには ctypefacet

/ etc/passwd形式のファイルを読み取る場合、次のプログラムは各:区切りのWordを個別に読み取ります。

#include <locale>
#include <iostream>


struct colon_is_space : std::ctype<char> {
  colon_is_space() : std::ctype<char>(get_table()) {}
  static mask const* get_table()
  {
    static mask rc[table_size];
    rc[':'] = std::ctype_base::space;
    rc['\n'] = std::ctype_base::space;
    return &rc[0];
  }
};

int main() {
  using std::string;
  using std::cin;
  using std::locale;

  cin.imbue(locale(cin.getloc(), new colon_is_space));

  string Word;
  while(cin >> Word) {
    std::cout << Word << "\n";
  }
}
42
Robᵩ

文字列の場合、 std::getline 異なる区切り文字を使用して読み込むオーバーロード。

数字の抽出では、区切り文字は実際には「空白」ではなく、数字で無効な文字です。

20
Ben Voigt

これは Robᵩ の答えの改善です。なぜなら、それは正しいものだからです(受け入れられなかったことに失望しています)。

必要なことは、ctypeが調べる配列を変更して、区切り文字を決定することです。

最も簡単なケースでは、独自に作成できます。

const ctype<char>::mask foo[ctype<char>::table_size] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ctype_base::space};

私のマシンでは'\n'は10です。配列の要素に区切り値ctype_base::spaceを設定しました。 ctypeで初期化されたfooは、'\n'または' 'ではなく、'\t'でのみ区切られます。

ctypeに渡される配列は、区切り文字だけでなく、文字、数字、記号、およびストリーミングに必要なその他のジャンクも定義するため、これが問題になります。 ( Ben Voigt の答えはこれに触れる。)だから私たちが本当にやりたいことはmodifya mask、ゼロから作成しないでください。

これは次のように実現できます。

const auto temp = ctype<char>::classic_table();
vector<ctype<char>::mask> bar(temp, temp + ctype<char>::table_size);

bar[' '] ^= ctype_base::space;
bar['\t'] &= ~(ctype_base::space | ctype_base::cntrl);
bar[':'] |= ctype_base::space;

ctypeで初期化されたbarは、'\n'および':'で区切られますが、' 'または'\t'では区切られません。

次のようにカスタムcinを使用するために、istreamまたは他のctypeをセットアップします。

cin.imbue(locale(cin.getloc(), new ctype<char>(data(bar))));

ctypesを切り替えることもでき、動作は途中で変更されます:

cin.imbue(locale(cin.getloc(), new ctype<char>(foo)));

デフォルトの動作に戻す必要がある場合は、次のようにします。

cin.imbue(locale(cin.getloc(), new ctype<char>));

Live example

15
Jonathan Mee

これはJonの答えの改善であり、 cppreference.com の例です。したがって、これは両方と同じ前提に従いますが、それらをパラメーター化された区切り文字と組み合わせます。

struct delimiter_ctype : std::ctype<char> {
    static const mask* make_table(std::string delims)
    {
        // make a copy of the "C" locale table
        static std::vector<mask> v(classic_table(), classic_table() + table_size);
        for(mask m : v){
            m &= ~space;
        }
        for(char d : delims){
            v[d] |= space;
        }
        return &v[0];
    }
    delimiter_ctype(std::string delims, ::size_t refs = 0) : ctype(make_table(delims), false, refs) {}
};

乾杯!

0
Josh C