باستخدام ' -- ' كعلامة نهاية الخيارات مع دفعة:: خيارات البرنامج

StackOverflow https://stackoverflow.com/questions/5475693

  •  14-11-2019
  •  | 
  •  

سؤال

الطريقة التقليدية للإشارة إلى نهاية الخيارات لبرامج سطر الأوامر هي مع الخيار --.كيف يمكنني الحصول على دفعة:: خيارات البرنامج للتعرف على هذا كخيار وقبول بقية سطر الأوامر كوسائط موضعية?ما يلي لا يعمل:

namespace po = boost::program_options;

po::positional_options_description posOpts;
posOpts.add("keywords", 1);
posOpts.add("input", 1);

std::vector<std::string> final_args;

po::options_description desc("Allowed Options");
desc.add_options()
  ...
  ("", po::value< std::vector<std::string> >(&final_args)->multitoken(), "end of options")
  ...
  ;

po::command_line_parser(argc, argv).options(desc).positional(posOpts).run();

إذا أعطيت foo bar كحجج ، لا أحصل على شيء في final_args (كما هو متوقع) ، ولكن أيضا عندما أعطي -- foo bar كحجج (عندما أتوقع أن أجد final_args[0] == "foo" و final_args[1] == "bar").أفترض هنا أن -- هي حجة طويلة مع السلسلة الفارغة كاسم الوسيطة.إذا ، بدلا من ذلك ، فإنه من المفترض أن تفسر على أنها حجة قصيرة ، مع - كاسم الحجة, كيف يمكنني تحديد ذلك?تغيير مواصفات الوسيطة من "" إلى ",-" لا يؤثر على النتيجة ، بقدر ما أستطيع أن أرى.

كيف يمكن للمرء الحصول على دفعة:: خيارات البرنامج للتعامل معها -- صحيح?

تحرير: إليك محاولة للقيام بما اقترحه تيم سيلفستر من خلال إنشاء extra_style_parser:

std::vector<po::option> end_of_opts_parser(std::vector<std::string>& args) {
  std::vector<po::option> result;

  std::vector<std::string>::const_iterator i(args.begin());
  if (i != args.end() && *i == "--") {
    for (++i; i != args.end(); ++i) {
      po::option opt;
      opt.string_key = "pargs";
      opt.original_tokens.push_back(*i);
      result.push_back(opt);
    }

    args.clear();
  }

  return result;
}

"pargs" تمت إضافته إلى خيارات مثل هذا:

("pargs", po::value< std::vector<std::string> >(&pargs), "positional arguments")

تشغيل هذا مع -- في قائمة الوسيطة يسبب أ required_option استثناء.(أحصل على نتائج مماثلة إذا بدلا من جعل po::option لكل الأرجنتين زائدة ، وأنا حزمة كل منهم في po::option::original_tokens في واحد po::option.)

هل كانت مفيدة؟

المحلول

كان لدي نفس السؤال ، لكنني تخلت عنه.

أعتقد أن طريقة القيام بذلك هي الاتصال program_options::command_line_parser::extra_style_parser(), ، تمريرها دالة تأخذ متجها من السلسلة بالرجوع وإرجاع متجه optionس (انظر ال style_parser اكتبصحف في كمدلاين.هب).

ستحتاج وظيفتك إلى اكتشاف أن الرمز المميز الأول هو " -- " ، وإنشاء رمز جديد option الكائن ، ضع كل ما تبقى من الرموز المميزة في الإدخال في optionمتجه القيمة وإفراغ متجه الإدخال.انظر program_options::detail::cmdline::parse_long_option, ، إلخ.، في libs/program_options/src/cmdline.cpp عن شيء لتبدأ.

ستحتاج على الأرجح إلى تسجيل قيمة خيار محددة لاستخدامها بحيث يمكنك بسهولة العثور على هذا الخيار الخاص option الكائن في نهاية التحليل واستخراج مجموعة من المعلمات غير الخيار إضافية منه.

أتمنى أن أعطيك بعض التعليمات البرمجية ولكن لم أحصل على القيام بذلك في الواقع ، انتهى بي الأمر مجرد أخذ المعلمات الإضافية واحد في كل سطر على ستدين.

تحرير:

شعرت بالسوء حيال توجيهك في اتجاه لم يحل المشكلة ، لذلك عدت وعملت.المشكلة هي أن إدخال الوسيطة الموضعية لم يتم إعداده لقبول رموز متعددة ولم تكن تملأ value.ال program_options يتوقع الكود كليهما أو لا يعمل.

وهنا رمز الكامل الذي يعمل بالنسبة لي:

#include <boost/program_options.hpp>
#include <iostream>

namespace po = boost::program_options;
typedef std::vector<std::string> stringvec;

std::vector<po::option> end_of_opts_parser(stringvec& args) {
  std::vector<po::option> result;
  stringvec::const_iterator i(args.begin());
  if (i != args.end() && *i == "--") {
    for (++i; i != args.end(); ++i) {
      po::option opt;
      opt.string_key = "pargs";
      opt.value.push_back(*i);      //  <== here
      opt.original_tokens.push_back(*i);
      result.push_back(opt);
    }
    args.clear();
  }
  return result;
}

int main(int argc, char* argv[])
{
    po::options_description desc("Allowed Options");
    desc.add_options()
        ("help,h", "produce help message")
        ("pargs", po::value<stringvec>()->multitoken(), "positional arguments");
    //                          and here     ^^^^^^^^^^^^^

    po::command_line_parser clparser(argc, argv);
    clparser.extra_style_parser(end_of_opts_parser);

    po::variables_map vm;
    po::store(clparser.options(desc).run(), vm);
    po::notify(vm);

    bool const help = !vm["help"].empty();
    std::cout << "help = " << help << " - ";

    // in addition, you don't need to use a separate vector of strings:    
    stringvec const& pargs = vm["pargs"].as<stringvec>();
    std::copy(pargs.begin(), pargs.end(),
        std::ostream_iterator<std::string>(std::cout, ","));

    return 0;
}

عند تشغيل مع -h -- foo bar baz يطبع help = 1 - foo,bar,baz,.

نصائح أخرى

أنا مرتبك قليلا لأن boost::program_options بالفعل يفعل هذا من تلقاء نفسه:

$ ./testprog --the-only-option=23 aa --unknown bb
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::unknown_option> >'
  what():  unknown option unknown
Aborted

$ ./testprog --the-only-option=23 -- aa --unknown bb
the only option: 23
positional: aa
positional: --unknown
positional: bb

البرنامج:

#include <boost/program_options.hpp>

#include <iostream>
#include <vector>

using namespace std;

namespace po = boost::program_options;

static bool handle_command_line(int argc, char *argv[])
{
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "Describe command line options")
        ("the-only-option", po::value<string>(), "some option")
        ;

    po::options_description hidden;
    hidden.add_options()
        ("positional", po::value<vector<string> >())
        ;

    po::options_description all_options;
    all_options.add(desc).add(hidden);

    po::positional_options_description p;
    p.add("positional", -1);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
              options(all_options).positional(p).run(), vm);
    po::notify(vm);

    if (vm.count("help")) {
        cout << "Usage: " << argv[0] << " [options] [args]" << endl;
        cout << desc << "\n";
        return false;
    }

    if (vm.count("the-only-option"))
        cout << "the only option: " << vm["the-only-option"].as<string>() << endl;

    if (vm.count("positional")) {
        const vector<string> &v = vm["positional"].as<vector<string> >();
        vector<string>::const_iterator it = v.begin();
        for (; it != v.end(); ++it)
            cout << "positional: " << *it << endl;
    }

    return true;
}

int main(int argc, char *argv[])
{
    if (!handle_command_line(argc, argv))
        return 1;
    return 0;
}

هناك بسيطة ، غير مرضية الحل:قبل تسليم argv إلى command_line_parser, تحقق ما إذا كان -- يحدث في ذلك.أنا إعادة تعيين argc موقف -- لإخفائه و الحجج زائدة من command_line_parser.ثم عند الانتهاء من تحليل ، والتعامل مع الموضعية الحجج بعد -- باليد.Blech!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top