我如何在c++中实现以下(Python伪代码)?

if argv[1].startswith('--foo='):
    foo_value = int(argv[1][len('--foo='):])

(例如,如果argv[1]是——foo=98,那么foo_value是98。)

更新:我很犹豫是否要研究Boost,因为我只是想对一个简单的小命令行工具做一个非常小的改变(我宁愿不学习如何链接并使用Boost进行一个小的改变)。


当前回答

冒着被批评使用C结构的风险,我确实认为这个sscanf示例比大多数Boost解决方案更优雅。如果您在任何有Python解释器的地方运行,则不必担心链接!

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    for (int i = 1; i != argc; ++i) {
        int number = 0;
        int size = 0;
        sscanf(argv[i], "--foo=%d%n", &number, &size);
        if (size == strlen(argv[i])) {
            printf("number: %d\n", number);
        }
        else {
            printf("not-a-number\n");
        }
    }
    return 0;
}

下面是一些示例输出,演示了该解决方案与等效的Python代码一样正确地处理前导/尾随垃圾,并且比使用atoi的任何方法都更正确(后者会错误地忽略非数字后缀)。

$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number

其他回答

如果你需要c++ 11兼容性而不能使用boost,这里有一个boost兼容的使用示例:

#include <iostream>
#include <string>

static bool starts_with(const std::string str, const std::string prefix)
{
    return ((prefix.size() <= str.size()) && std::equal(prefix.begin(), prefix.end(), str.begin()));
}

int main(int argc, char* argv[])
{
    bool usage = false;
    unsigned int foos = 0; // default number of foos if no parameter was supplied

    if (argc > 1)
    {
        const std::string fParamPrefix = "-f="; // shorthand for foo
        const std::string fooParamPrefix = "--foo=";

        for (unsigned int i = 1; i < argc; ++i)
        {
            const std::string arg = argv[i];

            try
            {
                if ((arg == "-h") || (arg == "--help"))
                {
                    usage = true;
                } else if (starts_with(arg, fParamPrefix)) {
                    foos = std::stoul(arg.substr(fParamPrefix.size()));
                } else if (starts_with(arg, fooParamPrefix)) {
                    foos = std::stoul(arg.substr(fooParamPrefix.size()));
                }
            } catch (std::exception& e) {
                std::cerr << "Invalid parameter: " << argv[i] << std::endl << std::endl;
                usage = true;
            }
        }
    }

    if (usage)
    {
        std::cerr << "Usage: " << argv[0] << " [OPTION]..." << std::endl;
        std::cerr << "Example program for parameter parsing." << std::endl << std::endl;
        std::cerr << "  -f, --foo=N   use N foos (optional)" << std::endl;
        return 1;
    }

    std::cerr << "number of foos given: " << foos << std::endl;
}

如果你已经在使用Boost,你可以使用Boost字符串算法+ Boost词法转换:

#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>

try {    
    if (boost::starts_with(argv[1], "--foo="))
        foo_value = boost::lexical_cast<int>(argv[1]+6);
} catch (boost::bad_lexical_cast) {
    // bad parameter
}

这种方法,就像这里提供的许多其他答案一样,适用于非常简单的任务,但从长远来看,您通常最好使用命令行解析库。Boost有一个(Boost. program_options),如果您碰巧已经在使用Boost,这可能是有意义的。

否则,搜索“c++命令行解析器”会得到许多选项。

在c++ 20中,starts_with作为std::string的成员函数可用,定义为:

constexpr bool starts_with(string_view sv) const noexcept;

constexpr bool starts_with(CharT c) const noexcept;

constexpr bool starts_with(const CharT* s) const;

所以你的代码可以是这样的:

std::string s{argv[1]};

if (s.starts_with("--foo="))

你也可以使用strstr:

if (strstr(str, substr) == substr) {
    // 'str' starts with 'substr'
}

但我认为它只适用于短字符串,因为当字符串实际上不是以'substr'开头时,它必须遍历整个字符串。

在c++ 11或更高版本中,可以使用find()和find_first_of()

使用find查找单个char的示例:

#include <string>
std::string name = "Aaah";
size_t found_index = name.find('a');
if (found_index != std::string::npos) {
    // Found string containing 'a'
}

示例使用find查找完整字符串并从位置5开始:

std::string name = "Aaah";
size_t found_index = name.find('h', 3);
if (found_index != std::string::npos) {
    // Found string containing 'h'
}

使用find_first_of()方法只搜索第一个字符,只搜索起始点:

std::string name = ".hidden._di.r";
size_t found_index = name.find_first_of('.');
if (found_index == 0) {
    // Found '.' at first position in string
}

更多关于find 关于find_first_of的更多信息

好运!