4

ユーザーの組み込み Python スクリプトを実行するための Python インターフェイスを公開する C++ プログラムがあります。

ユーザーは、実行する Python スクリプトのパスとコマンドライン引数を挿入します。次に、スクリプトが実行されます

boost::python::exec_file(filename, main_globals, main_globals)

コマンドライン引数を Python スクリプトに渡すには、Python C-API 関数を使用して設定する必要があります

PySys_SetArgv(int args, char** argv)

電話する前にexec_file()

ただし、これには、コマンドライン引数を含むユーザーの文字列をトークン化して引数のリストを取得し、それらを を介して Python インタープリターに戻す必要がありますPySys_SetArgv。これは単なる時間の無駄ではありません。この方法では、カスタム ユーザーのスクリプトでのみ定義される背後のロジックを知らずに、メインの C++ プログラムがコマンド ライン文字列をトークン化する責任を負わなければならないからです。

はるかに優れたクリーンなアプローチは、メタコードで次のようになります。

string command_line_args = '-v -p "filename" -t="anotherfile" --list="["a", "b"]" --myFunnyOpt'
exec_file( filename, command_line_args, ...)

Boost と Python C-API のドキュメントを何時間も調べましたが、役に立つものは何も見つかりませんでした。これを実現する方法があるかどうか、つまり、コマンド ライン引数の文字列全体を C++ から埋め込み Python スクリプトに渡す方法があるかどうか知っていますか?


アップデート:

以下のコメントでスティーブが提案したように、 https://stackoverflow.com/a/8965249/320369に従って、入力文字列のトークン化の問題を解決しました。

私の場合、私は使用しました:

// defining the separators
std::string escape_char = "\\"; // the escape character
std::string sep_char = " "; // empty space as separator
std::string quote_char = ""; // empty string --> we don't want a quote char'
boost::escaped_list_separator<char> sep( escape_char, sep_char, quote_char );

次のように、文字列を含むタプルも解析できるようにしたかったからです。

'--option-two=("A", "B")'

そして、あなたが使用する場合:

escaped_list_separator<char> sep('\\', ' ', '"');

元の投稿と同様に、引用符で囲まれた文字列が正しくトークン化されていません。

4

1 に答える 1

1

外部ファイルの実行に悪影響を及ぼさないため、ヘルパープログラムを使用して、シェルコマンドに解析を実行させることができます。ヘルパープログラムは次のようになります。

#include <stdio.h>
int main (int argc, char *argv[])
{
    for (int i = 1; i < argc; ++i) printf("%s\n", argv[i]);
    return 0;
}

次に、引数の単一の文字列をヘルパープログラムに送信し(おそらくを使用して)、解析された引数を読み戻すコードを作成できますpopen。各引数は別々の行にあります。

unparsed_line.insert(0, "./parser_helper ");
FILE *helper = popen(unparsed_line.c_str(), "r");
std::vector<std::string> args;
std::vector<const char *> argv;
std::string arg;
while (fgetstring(arg, helper)) {
    args.push_back(arg);
    argv.push_back(args.rbegin()->c_str());
}
pclose(helper);

fgetstringルーチンは私が書いたもので、fgetsとの間のクロスのようなものstd::getlineです。FILE *一度に1行から読み取り、std:string引数を入力します。

static bool
fgetstring (std::string &s, FILE *in)
{
    bool ok = false;
    std::string r;
    char buf[512];
    while (fgets(buf, sizeof(buf), in) != 0) {
        ++ok;
        r += buf;
        if (*r.rbegin() == '\n') {
            r.resize(r.size()-1);
            break;
        }
    }
    if (ok) s = r;
    return ok;
}

これに似たルーチンがあったSOの投稿を覚えているようですが、見つかりませんでした。後で見つけたら、投稿を更新します。

于 2012-06-03T21:30:26.980 に答える