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

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

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

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


当前回答

在c++ 17中,你可以使用std::basic_string_view,在c++ 20中使用std::basic_string::starts_with或std::basic_string_view::starts_with。

std::string_view与std::string相比的好处是——关于内存管理——它只保存一个指向“字符串”(连续的char类对象序列)的指针,并且知道它的大小。示例:不移动/复制源字符串,只获取整数值:

#include <exception>
#include <iostream>
#include <string>
#include <string_view>

int main()
{
    constexpr auto argument = "--foo=42"; // Emulating command argument.
    constexpr auto prefix = "--foo=";
    auto inputValue = 0;

    constexpr auto argumentView = std::string_view(argument);
    if (argumentView.starts_with(prefix))
    {
        constexpr auto prefixSize = std::string_view(prefix).size();
        try
        {
            // The underlying data of argumentView is nul-terminated, therefore we can use data().
            inputValue = std::stoi(argumentView.substr(prefixSize).data());
        }
        catch (std::exception & e)
        {
            std::cerr << e.what();
        }
    }
    std::cout << inputValue; // 42
}

其他回答

如果你已经在使用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结构的风险,我确实认为这个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

你也可以使用strstr:

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

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

使用rfind重载,接受搜索位置pos参数,并为其传递0:

std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) { // pos=0 limits the search to the prefix
  // s starts with prefix
}

谁还需要别的东西?纯STL !

许多人将其误解为“在整个字符串中反向搜索前缀”。这将给出错误的结果(例如string("tititito").rfind("titi")返回2,因此当与== 0进行比较时将返回false),并且它将是低效的(查看整个字符串而不是只查看开头)。但是它没有这样做,因为它将pos参数传递为0,这将搜索限制在该位置或更早的位置进行匹配。例如:

std::string test = "0123123";
size_t match1 = test.rfind("123");    // returns 4 (rightmost match)
size_t match2 = test.rfind("123", 2); // returns 1 (skipped over later match)
size_t match3 = test.rfind("123", 0); // returns std::string::npos (i.e. not found)
std::string text = "--foo=98";
std::string start = "--foo=";

if (text.find(start) == 0)
{
    int n = stoi(text.substr(start.length()));
    std::cout << n << std::endl;
}