2012-01-22 9 views
1

私はboost::program_optionsを使用して私のコマンドラインを解析しています。今、私は、例えば、すべての行にコマンドラインオプションを含む、ファイルを表す--script引数によって、バッチ実行のサポートを追加してい:C++:文字列をコマンドライン引数に分解する(解析しない)方法は?

--src="\"z:\dev\veds\sqlexpress\Run 1.ved\"" --src-kind=bla --yz 
--src=z:\dev\veds\sqlexpress\db.ebf 
--src=z:\dev\veds\sqlexpress\db2.mdf 
--src=db3 
--src="\"z:\dev\veds\sqlite\Run 41 (Run 23).ved\"" 
--src=z:\dev\veds\sqlite\ws_results_db_2012_01_15_18_37_03.db3 
--src=z:\dev\veds\mysql\10.ved 
--src=z:\dev\veds\mysql\db 

ファイルの各行には、私のツールの単一の実行を表し、この特定の実行のコマンドラインオプションを一覧表示します。

問題は、スクリプトファイルを読むと完全な行が得られ、個々のコマンドラインオプションに分割されないことです。しかし、boost::program_optionsを使用するには、argcargvが必要です。つまり、コマンドラインを別のオプションに分割することに依存します。

一部の値には空白が含まれているため、二重引用符で囲まれており、二重引用符で囲まれています。

一方、高価なブートストラップのために、OSコマンドプロンプトから各コマンドラインオプションのツールを実行する必要はありません。これは最初にスクリプト機能を導入した理由です。

OSと同じ方法で行をコマンドライン引数に分割する簡単な方法はありますか?

ありがとうございました。

+0

どのような混乱!バックスラッシュはエスケープ文字の後に引用符が続きますが、その後に引用符が続く場合のみです。文字列の最後に引用符の直前にバックスラッシュがある場合はどうなりますか?私は元のデータが実際にあなたが与えるログファイルスニペットから回復可能であるとは思わない。 –

+0

プラットフォーム固有のソリューションを受け入れる場合、[CommandLineToArgvW](http://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx)があります。さもなければ、ネットを検索するにはコマンドラインからargvに行くための多くの解決策があります。 –

+0

皆、これは非常に実際的な例です。ウィンドウシェルはバックスラッシュを気にしないので、アプリケーションにそのまま渡します。文字列は 'boost :: filesystem :: path'に入力されます。これは、スペースを入れるために明示的に引用する必要があります。したがって、エスケープ文字をエスケープ文字として解釈するのは、 。 – mark

答えて

0

Boostのドキュメントには、Response Filesが含まれています。それは、あなたが望むものに近いでしょう。ただし、スペースの解析を含む「いくつかの制限があります」と言います。

また、ファイルからオプションをロードするparse_config_file()もあります。ここでは、コマンドラインと同じ構文をファイル内に持つことをあきらめています。それらのインクルードされた実装では、プログラム呼び出しごとに1つの「コマンド呼び出し」しかサポートしません。しかし、私はあなたがそれをどうやって見て、そのコードの一部をコピーすることができると確信しています。私は、これは余分な作業の恐ろしい量ではなく、それはあなたが各ジョブに明示的な名前を持っていることの1つの余分な利益を与える賭け

[job1] 
src=z:\dev\veds\sqlexpress\Run 1.ved 
src-kind=bla 
y= 
z= 

[job2] 
src=z:\dev\veds\sqlexpress\db.ebf 

[another_job] 
src=z:\dev\veds\sqlexpress\db2.mdf 

:私があなただったら、私はこのようなの.ini構文をサポートするためにそれを調整するかもしれません走るBoost自身のparse_config_file()はオプション名のプレフィックスとしてセクション名(角カッコ内)を使用しますが、これは必須ではありません。単純な.ini構文を保持するために再利用するかもしれません。

編集:もっと簡単にしたいですか? OK。クォートとスペースに関するコマンドラインと同じ構文をファイルに持たせるという考え方を放棄してください。引数内のスペースをサポートする必要がある場合は、オプション間に適切な区切り文字(例えば、;)を決定します。最初にARGV [1,2,3]を作成する;

--src=z:\dev\veds\sqlexpress\Run 1.ved; --src-kind=bla; --yz 
--src=z:\dev\veds\sqlexpress\db.ebf 
--src=z:\dev\veds\sqlexpress\db2.mdf 

スプリット:のargc/argvのペアには、このような何かを回すと(見つける)またはブースト::のstd ::文字列を使用してトークナイザ十分に簡単でなければなりませんプログラムの独自のargv [0]を "fake" argv [0]にコピーして、Boostを使ってオプションを解析してください。

+0

これは "線を壊す簡単な方法"からかなり離れています。 – mark

+0

C++へようこそ。 –

+0

私はC++で何かをしなければならないとは思わない。 – mark

0

チェックこのアウト:: C++クックブック分割文字列(レシピ4.6)

例4-10。

template<typename T> 
void split(const basic_string<T>& s, T c, 
      vector<basic_string<T> >& v) { 
    basic_string<T>::size_type i = 0; 
    basic_string<T>::size_type j = s.find(c); 

    while (j != basic_string<T>::npos) { 
     v.push_back(s.substr(i, j-i)); 
     i = ++j; 
     j = s.find(c, j); 

     if (j == basic_string<T>::npos) 
     v.push_back(s.substr(i, s.length())); 
    } 
} 

例4-11 - 区切られた文字列

#include <string> 
#include <vector> 
#include <functional> 
#include <iostream> 

using namespace std; 

void split(const string& s, char c, 
      vector<string>& v) { 
    string::size_type i = 0; 
    string::size_type j = s.find(c); 

    while (j != string::npos) { 
     v.push_back(s.substr(i, j-i)); 
     i = ++j; 
     j = s.find(c, j); 

     if (j == string::npos) 
     v.push_back(s.substr(i, s.length())); 
    } 
} 

int main() { 
    vector<string> v; 
    string s = "Account Name|Address 1|Address 2|City"; 

    split(s, '|', v); 

    for (int i = 0; i < v.size(); ++i) { 
     cout << v[i] << '\n'; 
    } 
} 

を分割します。ブースト

#include <iostream> 
#include <string> 
#include <list> 
#include <boost/algorithm/string.hpp> 

using namespace std; 
using namespace boost; 

int main() { 

    string s = "one,two,three,four"; 
    list<string> results; 

    split(results, s, is_any_of(",")); // Note this is boost::split 

    for (list<string>::const_iterator p = results.begin(); 
     p != results.end(); ++p) { 
     cout << *p << endl; 
    } 
} 

で文字列を分割する -

template<typename Seq, 
     typename Coll, 
     typename Pred> 
Seq& split(Seq& s, Coll& c, Pred p, 
     token_compress_mode_type e = token_compress_off); 

私は、テキスト(本からコピーすることは違法/ペースト)を共有する自由でないんだけど、これらの例はかなりexplainativeです。テキストを見たい場合は、本を参照する必要があります。

ジェフCogswell、クリストファーDiggins、ライアン・スティーブンス、ジョナサンTurkanis

出版社が4.6

のC++クックブック

これら二つの例は、レシピから採取した:オライリー

パブ日:2005年11月

ISBN:0-596-00761-2

+0

私はもっと簡単な方法を見つけたと思う - 自分の答えを見てください。 – mark

1

OK、わかった。ここに私のコードは次のとおりです。

string script; 
    { 
    ifstream file(scriptPath.c_str()); 
    file.seekg(0, ios::end); 
    script.resize(file.tellg()); 
    file.seekg(0, ios::beg); 
    file.read(const_cast<char *>(script.c_str()), script.size()); 
    } 
    boost::replace_all(script, "\\", "\\\\");  // Escape the backslashes 
    boost::replace_all(script, "\\\\\"", "\\\""); // Except for those escaping the quotes 
    boost::trim_right_if(script, is_space_or_zero); // There are extra '\0' in the string, because the file is read as text, but its length was computed as binary 
    vector<string> lines; 
    boost::split(lines, script, boost::is_any_of("\n")); // I prefer getting a string line iterator here, the question is how? 
    escaped_list_separator<char> sep('\\', ' ', '"'); 
    int res = 0; 
    BOOST_FOREACH (const string& line, lines) 
    { 
    // reset the command line variables here, since this is like a new execution 

    // Tokenize the command line, respecting escapes and quotes 
    tokenizer<escaped_list_separator<char>> tok(line, sep); 
    vector<string> args(tok.begin(), tok.end()); 

    po::variables_map vm; 
    po::store(po::command_line_parser(args).options(options).run(), vm); 

    res += run(vm); 
    } 

私はラインを破るhttp://www.boost.org/doc/libs/1_48_0/libs/tokenizer/を使用しています。非常にうまく動作します。

+0

他の人のためのヒント: 'args.erase(std :: remove_if(args.begin()、args.end()、[](std :: string const&s){return s.empty();})、args .end()); 'escaped_list_separatorに** empty_token_policy **がありません**のように** char_separator ** – 5andr0

関連する問題