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桁以上の数字についてどうするか。私はあらゆる種類を想像し始めています forループは非常に複雑で、ここの誰かが共有できるかどうか疑問に思っています このデータを抽出して使用するよりインテリジェントな方法を私と一緒に。
解決
stringstream
を使用し、ストリーム抽出演算子を使用して整数を取得できます。
string s("12 34");
istringstream ss(s);
int x, y;
ss >> x >> y;
これは宿題なので、可能性を探り、完全なものを見つけ出すことをお勧めします 自分用のコード。
他のヒント
あなたは全体を見て圧倒されているようです。細かく...タスクに分割します。あなたがやろうとしていることは、ここでは別個の機能のようです。
- トークン化
- 頂点の解析
- エッジの解析
- 頂点の実行
- エッジでの実行
それは5つの関数です。
パイプ(|)に基づいてトークン化したいので、パイプに基づいて部分文字列を取得し、それぞれの側を適切なパーサーに渡し、コンマなどで解析します。
あなたのためにそれをするつもりはありませんが、うまくいけば、正しい方向に考えさせることができます。プログラミングの学習は、特定の言語についてではなく、あなたの考え方を変えることです。
これまで使用したことはありませんが、Boost tokenizer クラス。すべてのforループなしで、簡単にコンポーネントに分割できます。
あなたのために宿題をすることなく、これは良いスタートを切るでしょう。頂点リストを解析するための基本的なワークフローを説明しました。エッジリストを自分で実行できるはずです。また、エラーのチェックはユーザーに任せます。たとえば、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"));
}
この種の構文解析は、再帰降下テクニックを使用するとかなり単純です(面倒ですが)。アイデアは、解析対象の言語を論理ユニットに分離し、それらの各ユニットを解析する関数を作成することです。
例で「| 1,2,3,4,15 |(1-&gt; 2)、(3-&gt; 2)、(4-&gt; 15)|」を計算すると、文字列全体が「ポリゴン」である場合、parsePolygon()を記述します。これは次のようになります。
void parsePolygon (Buffer& b)
{
parseVertices (b);
parseEdges (b);
}
Bufferが文字列を実行するクラスであると仮定しましょう。次の2つの基本操作が必要です。次の文字を消費せずに覗く、および次の文字を消費します。
parseVerticesは次のようになります。
void parseVertices (Buffer& b)
{
if (b.peek() != '|') { /* error */ }
b.consume (); // burn the '|'
parseVertexList (b);
if (b.peek() != '|') { /* error */ }
b.consume (); // burn the '|'
}
明らかにエラーをもっとうまく処理したいと思うでしょう。ストリームでエラーが発生した場合、エラーコードをコールスタックに渡すか、例外をスローする必要があります。
さらに2つの例... parseVertexListとparseNumberは次のようになります。
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関数が実際にaddVertex呼び出しを行う上記のように、処理と解析を混在させることができます。
これは、実際には手動解析の最も簡単な方法の1つだと思います。理想的には、ブーストスピリットやpyparsing、lex / yaccなどの生成されたパーサーを常に使用できますが、特に宿題の場合、人生は必ずしもそれほど良いとは限りません。
また、上記の手法は一部の解析状況では過剰になりすぎることに注意する価値があると思います。
stringstream
を使用します。 istringstream
で数値を読み取るためのそのページの例に注意してください。
boostでプレイする口実として、この問題を必ず使用します。精神!この小さな言語の小さな文法を書くのはとても楽しいはずです。