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

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

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

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


当前回答

使用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)

其他回答

如果你已经在使用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++ 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
}

好的,为什么要复杂地使用库之类的东西?c++字符串对象重载[]操作符,所以你可以只比较字符。就像我刚才做的,因为我想列出目录中的所有文件忽略不可见文件和。和。pseudofiles。

while ((ep = readdir(dp)))
{
    string s(ep->d_name);
    if (!(s[0] == '.')) // Omit invisible files and .. or .
        files.push_back(s);
}

就是这么简单。

假设两个字符串——argv[1]和"——foo"——都是C字符串,@FelixDombek的答案无疑是最好的解决方案。

然而,看到其他答案,我认为值得注意的是,如果你的文本已经作为std::string可用,那么一个简单的、零拷贝的、最大效率的解决方案存在,到目前为止还没有提到:

const char * foo = "--foo";
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(strlen(foo));

如果foo已经是一个字符串:

std::string foo("--foo");
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(foo.length());

从c++ 11开始,std::regex_search还可以用来提供更复杂的表达式匹配。下面的示例还通过std::stof处理浮点数,并将其转换为int。

然而,如果前缀不匹配,下面所示的parseInt方法可能会抛出std::invalid_argument异常;这可以很容易地根据给定的应用程序进行调整:

#include <iostream>
#include <regex>

int parseInt(const std::string &str, const std::string &prefix) {
  std::smatch match;
  std::regex_search(str, match, std::regex("^" + prefix + "([+-]?(?=\\.?\\d)\\d*(?:\\.\\d*)?(?:[Ee][+-]?\\d+)?)$"));
  return std::stof(match[1]);
}

int main() {
    std::cout << parseInt("foo=13.3", "foo=") << std::endl;
    std::cout << parseInt("foo=-.9", "foo=") << std::endl;
    std::cout << parseInt("foo=+13.3", "foo=") << std::endl;
    std::cout << parseInt("foo=-0.133", "foo=") << std::endl;
    std::cout << parseInt("foo=+00123456", "foo=") << std::endl;
    std::cout << parseInt("foo=-06.12e+3", "foo=") << std::endl;

//    throw std::invalid_argument
//    std::cout << parseInt("foo=1", "bar=") << std::endl;

    return 0;
}

正则表达式模式的神奇之处将在下面的回答中详细说明。

编辑:之前的答案没有执行到整数的转换。