13

次の形式のデータがあります。

4:どうしますか?
10:お誕生日おめでとう
1:紫猿食器洗い機
200:トランペッタースワンの祖先の領土の命令

番号は1から999の範囲で、文字列の長さは最大255文字です。私はC++を初めて使用し、ストリームの>>演算子を使用してフォーマットされたデータを抽出することを推奨しているソースがいくつかあるようですが、文字列を抽出する場合は、最初の空白文字で停止します。改行またはファイルの終わりでのみ文字列の解析を停止するようにストリームを構成する方法はありますか?行全体を抽出する方法があるのを見ましたが、getlineそれでも手動で分割する必要find_first_ofがありますね。

STLのみを使用してこの形式のデータを解析する簡単な方法はありますか?

4

5 に答える 5

14

C ++文字列ツールキットライブラリ(StrTk)には、問題に対する次の解決策があります。

#include <string>
#include <deque>
#include "strtk.hpp"

int main()
{
   struct line_type
   {
      unsigned int id;
      std::string str;
   };

   std::deque<line_type> line_list;

   const std::string file_name = "data.txt";

   strtk::for_each_line(file_name,
                        [&line_list](const std::string& line)
                        {
                           line_type temp_line;
                           const bool result = strtk::parse(line,
                                                            ":",
                                                            temp_line.id,
                                                            temp_line.str);
                           if (!result) return;
                           line_list.push_back(temp_line);
                        });

   return 0;
}

その他の例はここにあります

于 2010-12-30T20:12:41.713 に答える
10

についてはすでに説明しましstd::getlineたが、おそらく役立つと思われる詳細については言及されていません。を呼び出すときにgetline、入力の終わりとして処理する文字を指定するパラメーターを渡すこともできます。あなたの番号を読むために、あなたは使うことができます:

std::string number;
std::string name;

std::getline(infile, number, ':');
std::getline(infile, name);   

これにより、「:」までのデータがに入れられ、「:」がnumber破棄され、残りの行が。に読み込まれnameます。

データの読み取りに使用したい場合は>>、それも実行できますが、それは少し難しく、ほとんどの人が決して触れない標準ライブラリの領域を掘り下げます。ストリームには、locale数値のフォーマットや(重要な)「空白」を構成するものの決定などに使用される関連付けがあります。独自のロケールを定義して、「:」を空白として定義し、スペース( "")を空白ではないものとして定義できます。そのロケールを使用するようにストリームに指示すると、データを直接読み取ることができます。

#include <locale>
#include <vector>

struct colonsep: std::ctype<char> {
    colonsep(): 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['\n'] = std::ctype_base::space;
        return &rc[0];
    }
};

これを使用するために、ストリームにロケールを「注入」します。

#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>

typedef std::pair<int, std::string> data;

namespace std { 
    std::istream &operator>>(std::istream &is, data &d) { 
       return is >> d.first >> d.second;
    }
    std::ostream &operator<<(std::ostream &os, data const &d) { 
        return os << d.first << ":" << d.second;
    }
}

int main() {
    std::ifstream infile("testfile.txt");
    infile.imbue(std::locale(std::locale(), new colonsep));

    std::vector<data> d;

    std::copy(std::istream_iterator<data>(infile), 
              std::istream_iterator<data>(),
              std::back_inserter(d));

    // just for fun, sort the data to show we can manipulate it:
    std::sort(d.begin(), d.end());

    std::copy(d.begin(), d.end(), std::ostream_iterator<data>(std::cout, "\n"));
    return 0;
}

これで、ライブラリのその部分がそれほど無視されている理由がわかりました。理論的には、標準ライブラリを使用して作業を行うことは素晴らしいことですが、実際には、ほとんどの場合、代わりにこの種の作業を自分で行う方が簡単です。

于 2010-02-26T16:27:33.553 に答える
10

を使用する前に番号を読み取ることができますstd::getline。これは、ストリームから読み取り、std::stringオブジェクトに格納します。このようなもの:

int num;
string str;

while(cin>>num){
    getline(cin,str);

}
于 2010-02-26T01:16:12.520 に答える
2

getlineを使用してデータを1行ずつ(行全体)読み取り、解析するだけです。
解析するには、find_first_of()を使用します

于 2010-02-26T01:18:03.770 に答える
2
int i;
char *string = (char*)malloc(256*sizeof(char)); //since max is 255 chars, and +1 for '\0'
scanf("%d:%[^\n]s",&i, string); //use %255[^\n]s for accepting 255 chars max irrespective of input size
printf("%s\n", string);

そのCとC++でも動作します。scanfはより詳細な制御を提供しますが、エラー管理は提供しません。したがって、注意して使用してください:)。

于 2010-02-26T01:09:20.037 に答える