2009-05-06 40 views
1

私は、文字列を パラメータとして受け入れてグラフを構築するために使用するグラフクラスのコンストラクタを作成しようとしています。C++での文字列の解析

文字列のフォーマットは、次のとおりです。|vertex list|Edges list| |1,2,3,4,15|(1->2),(3->2),(4->15)|

アイデアは、コンストラクタは次のアクション(頂点リスト に頂点を挿入して、エッジリストにエッジを挿入する)を実行するために知っている文字列から値を取得し、その後 ということです。

addVertex(1) 
addVertex(2) 
addVertex(3) 
addVertex(4) 
addVertex(15) 
addEdge(1,2) 
addEdge(3,2) 
addEdge(4,15) 

文字列をスキャンするための "for"ループをいくつか作成しただけですが、わかりません。 2桁(またはそれ以上)の数字について何をするか。私はすべての種類のループを真剣に複雑にしているすべての種類の を想像し始めています。ここに誰もがこのデータを抽出して使用するために私と一緒に を共有できるかどうか疑問に思っています。

+0

入力形式はあなたによって発明されていますか?もしそうなら、何かに簡単に変更してください。 –

+0

同意する必要があります。この構文は、不必要に複雑です。より簡単な形式は、 (1 2 3 4 15)([1 2] [3 2] [4 15])のようになります。 – rlbond

+0

この形式は宿題に指定されています。私はそれを変更することができたらいいと思っています... – Meir

答えて

2

stringstreamを使用し、ストリーム抽出演算子を使用して整数を取得できます。

string s("12 34"); 
istringstream ss(s); 
int x, y; 
ss >> x >> y; 

これは宿題ですので、私は可能性を探求し、自分自身のための完全な コードを把握するためにあなたを促します。

+0

stringstreamでは、空白を区切ることが保証されていないため、ここでの作業がずっと簡単にはなりません。誰も整数について何も言わなかった。彼らはほんの一例でした。 – wilhelmtell

+0

Stringstreamは良い解決策のようですが、どのようにコンマを扱うのですか?私のリストはスペースで区切られていませんが、コンマで区切られています。例:(12,34) – Meir

+0

あなたは 's >> >> >>カンマ>> y;ここで「カンマ」はcharです。 – dirkgently

2

私はかつてこれを使ったことはありませんが、Boost tokenizerクラスがあります。あなたはfor-loopingがなければ、簡単にコンポーネントをコンポーネントに分解できます。

+0

boost tokenizerはこのケースでは素晴らしいオプションです。 +1 –

+0

Boost Tokenizerは、文字列を分割するのに最適です。あなたがこの状況でそれを使用しないとしても、未来を知ることは良いことです。 –

0

stringstreamを使用してください。そのページの例では、数字をistringstreamで読むことに注意してください。

6

あなたはすべてを見て圧倒されているようです。それを分割してタスクに分解してください。あなたがしようとしているのは、ここでは別々の機能だと思われます。

  1. トークン化
  2. 解析頂点
  3. 頂点
  4. 5つの機能、多かれ少なかれだエッジ

  • 実行上のエッジ
  • 実行の解析。

    パイプ(|)に基づいてトークン化したいので、パイプに基づいて部分文字列を取り出し、適切なパーサに渡し、コンマで解析するなどです。

    あなたのためにはやっていませんが、うまくいけば、正しい方向に考えさせることができます。プログラムを学ぶことは、特定の言語についてではなく、あなたの考え方を変えることです。

  • +3

    +1は宿題にやさしいアドバイスです。 –

    1

    あなたの宿題をすることなく、これはあなたに良いスタートを与えるでしょう。頂点リストを解析するための基本的な作業フローを与えました。あなた自身でエッジリストを作成できるはずです。また、parseVertex()のように、エラーチェックを残しておきます。無効な文字に遭遇したときにエラーを出すことができます。

    void skipWhiteSpace(const char*& first , const char* last) { 
        // do whatever need to be done to skip white space 
    } 
    
    // parse integer only, no error checking is performed 
    bool parseVertex(const char*& first , const char* last) { 
        skipWhiteSpace(first, last); 
        const char* numBegin = first; 
        for (; first != last && ::isdigit(static_cast<unsigned char>(*first)); 
         ++first) {} 
        if (numBegin != first) { 
         std::cout << "addVertex(" << std::string(numBegin, first) << ")" << std::endl; 
         return true; 
        } 
    
        return false; 
    } 
    
    bool parseComma(const char*& first , const char* last) { 
        skipWhiteSpace(first, last); 
        if (first != last && ',' == *first) { 
         ++first; 
         return true; 
        } 
    
        return false; 
    } 
    
    // VL := V (, VL) 
    // a vertex list (VL) is a vertex (V) followed by a comma than another vertex list 
    bool parseVertexList(const char*& first, const char* last) { 
        if (parseVertex(first, last)) { 
         parseComma(first, last) && parseVertexList(first, last); 
         return true; 
        } 
    
        return false; 
    } 
    } 
    
    void test() { 
        const char* str = "1,2,3,4,15"; 
        parseVertexList(str, str + sizeof("1,2,3,4,15")); 
    } 
    
    +0

    コードを本当にありがとう。 sstreamはもう少しエレガントなようですが、あなたの答えは素晴らしいです。 – Meir

    0

    私は確かにboost spiritで遊ぶためにこの問題を使用します!この小さな言葉のための小さな文法を書くことは、すごく楽しいはずです。

    1

    この種のものを解析することは、再帰的な降下手法を使用すると非常に簡単です(面倒ですが)。その考え方は、解析される言語を論理ユニットに分割し、それらのユニットのそれぞれを解析する関数を記述することです。

    "| 1,2,3,4,15 |(1-> 2)、(3-> 2)、(4-> 15)|"文字列全体が「ポリゴン」であること、私たちはこのようになりますこれは、)(parsePolygonを書きたい:

    void parsePolygon (Buffer& b) 
    { 
        parseVertices (b); 
        parseEdges (b); 
    } 
    

    のバッファがあなたの文字列を通るクラスであると仮定しましょう。 2つの基本的な操作が必要です:次の文字を消費せずに覗いて、次の文字を消費します。

    parseVerticesは、次のようになります。

    void parseVertices (Buffer& b) 
    { 
        if (b.peek() != '|') { /* error */ } 
        b.consume(); // burn the '|' 
        parseVertexList (b); 
        if (b.peek() != '|') { /* error */ } 
        b.consume(); // burn the '|' 
    } 
    

    あなたは明らかに、より良いエラーを処理したいと思います。ストリームにエラーが発生した場合は、エラーコードを呼び出しスタックに渡すか、例外をスローする必要があります。これはすべての非常に迅速かつ汚いです

    void parseVertexList (Buffer& b) 
    { 
        addVertex (parseNumber (b)); 
        while (b.peek() == ',') 
        { 
        b.consume(); // eat the comma 
        addVertex (parseNumber (b)); 
        } 
    } 
    
    int parseNumber (Buffer& b) 
    { 
        char accum[80] = { '0' }; // sensible default in case of failure 
        int accumPos = 0; 
        while (isDigit (b.peek()) 
        { 
        accum[accumPos++] = b.consume(); 
        } 
        return atoi(accum); 
    } 
    

    、うまくいけば、それはあなたの技術がどのように動作するかのアイデアを与える:

    さらに二つの例... parseVertexListとparseNumberは、次のようになります。上記のように処理を混在させることができます。ここでparseVertexList関数は実際にaddVertex呼び出しを行います。

    これは本当に手動で解析する最も簡単な方法の1つだと思います。理想的には、boost spiritやpyparsingやlex/yaccのような生成されたパーサーを常に使用できると思っていますが、人生は常に宿題にとってはそれほど良いとは限りません。

    また、私は上記の手法が構文解析の状況によっては過度に多くなる可能性があることに注意してください。

    +0

    ご協力いただきありがとうございます。もう少し複雑なものを解析すると、あなたのソリューションがどれほど素晴らしいかを知ることができます。すてきな一日を! – Meir

    +0

    私はちょうど別のプロジェクトの助けにこれを使用しました。本当にありがとう! – Meir