问答中心分类: C++如何检查 C++ std::string 是否以某个字符串开头,并将子字符串转换为 int?
0
匿名用户 提问 1天 前

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

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

(例如,如果argv[1]--foo=98, 然后foo_value98.)
更新:我对研究 Boost 犹豫不决,因为我只是想对一个简单的小命令行工具进行非常小的更改(我宁愿不必学习如何链接和使用 Boost 进行微小的更改) .

manlio 回复 1天 前

This也很有趣。

manlio 回复 1天 前

C++ 20starts_with

manlio 回复 1天 前

@LouisGo 感谢上帝。不再rfind()

21 Answers
0
Thomas 回答 1天 前

你会这样做:

std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
    foo_value = std::stoi(arg.substr(prefix.size()));

寻找像 Boost.ProgramOptions 这样为您执行此操作的库也是一个好主意。

Tom 回复 1天 前

最大的问题是atoi("123xyz")返回123,而 Python 的int("123xyz")抛出异常。

Roopesh Majeti 回复 1天 前

我们可以做的解决方法是使用 sscanf() 并将结果与​​原始结果进行比较,以决定是继续还是抛出异常。

Tom 回复 1天 前

或者只是更换atoistrtol或者strtoll,这让我们可以检测输入值中的错误情况。

Calmarius 回复 1天 前

这是比rfind一种依赖于优化的工作。

Yuval 回复 1天 前

@Calmariusrfind解决方案不依赖于任何优化。rfind根据定义,它的行为是在给定时只查看单个索引pos=0,因此它始终是一种有效的检查。哪种语法更令人愉悦是一个偏好问题。

0
Felix Dombek 回答 1天 前

为了完整起见,我将提到 C 的方式来做到这一点:

如果str是你的原始字符串,substr是您要检查的子字符串,然后
strncmp(str, substr, strlen(substr))
将返回0如果str以。。开始substr.功能strncmpstrlen在 C 头文件中<string.h>

(最初由 Yaseen Rauf 发表这里, 添加了标记)
对于不区分大小写的比较,请使用strnicmp代替strncmp.
这是 C 的方法,对于 C++ 字符串,您可以使用相同的函数,如下所示:

strncmp(str.c_str(), substr.c_str(), substr.size())
Force Gaia 回复 1天 前

确实,每个人似乎都只是去“使用 boost”,我感谢一个 stl 或 OS 库版本

Avishai Y 回复 1天 前

是的。但是,它假定字符串中没有空字符。如果不是这种情况 – 应该使用memcmp()

Adham Zahran 回复 1天 前

为什么有人会使用这个简单漂亮的解决方案以外的任何东西?

0
Ferruccio 回答 1天 前

如果您已经在使用 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++ 命令行解析器”将产生许多选项。

cyrilchampier 回复 1天 前

“boost::algorithm::starts_with”而不是“boost::starts_with”?

Ferruccio 回复 1天 前

@nerith:似乎他们都工作。我一直使用较短的形式。

Alex Bitek 回复 1天 前

boost::starts_with 和 boost::algorithm::starts_with 是一回事。如果您查看此文件的末尾svn.boost.org/svn/boost/trunk/boost/algorithm/string/…你会看到这个:// 使用 algorithm::starts_with 将名称拉入 boost 命名空间; […]

Tobi 回复 1天 前

为字符串前缀检查引入巨大的依赖关系就像用大炮射鸟一样。

Glenn Maynard 回复 1天 前

当有人问如何在 C++ 中进行简单的字符串操作时,“使用 Boost”总是错误的答案。

uglycoyote 回复 1天 前

负 1 表示建议 Boost

Alex Che 回复 1天 前

如果您已经在项目中使用了 boost,那么在这里使用 boost 是正确的。

qwattash 回复 1天 前

如果这是您决定首先链接 boost 的原因,那么为此使用 boost 是错误的,如果您已经出于其他原因使用 boost,我不明白为什么这会是一个大问题。

NuSkooler 回复 1天 前

答案的前缀是“如果您使用的是 Boost……”。显然这是正确的答案“…如果您使用的是 Boost”。如果没有,请查看@Thomas 的建议

Jepessen 回复 1天 前

如果您使用 C++,Boost 始终是一个解决方案。当不需要做的时候,就没有必要重新发明轮子。我们工作,我们不做家庭作业。

Jepessen 回复 1天 前

Boost 不是一个 BIG 库.. 是一组大大小小的库。如果一个小的 boost 库可以解决这个问题,我看不出有什么理由避免它。

0
Hüseyin Yağlı 回答 1天 前

我自己使用的代码:

std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
    std::string argumentValue = argument.substr(prefix.size());
}
Ben Bryant 回复 1天 前

最简洁且仅依赖于 std::string,除了在最终 substr 末尾删除可选和误导性的 argument.size()。

Hüseyin Yağlı 回复 1天 前

@ben-bryant:感谢您的提醒。不知道这是可选的。

Felix Dombek 回复 1天 前

使用substr导致不必要的复制。这str.compare(start, count, substr)中使用的方法托马斯的回答效率更高。razvanco13 的回答有另一种避免复制的方法std::equal.

Parthian Shot 回复 1天 前

@HüseyinYağlıThomas uses atoi which is only for windows嗯?atoi自从…以来一直是 C 标准库函数。事实上,atoi不好——不是因为它是特定于 Windows 的——而是因为它是 (1) C,而不是 C++,并且 (2) 即使在 C 中也不推荐使用(你应该使用strtol或其他相关功能之一。因为atoi没有错误处理。但是,无论如何,这只是在 C 中)。

0
matiu 回答 1天 前

没有人使用 STL算法/不匹配功能尚未。如果返回 true,prefix 是 'toCheck' 的前缀:

std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()

完整的示例程序:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "Will print true if 'prefix' is a prefix of string" << std::endl;
        return -1;
    }
    std::string prefix(argv[1]);
    std::string toCheck(argv[2]);
    if (prefix.length() > toCheck.length()) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "'prefix' is longer than 'string'" <<  std::endl;
        return 2;
    }
    if (std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()) {
        std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck << '"' << std::endl;
        return 0;
    } else {
        std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"' << toCheck << '"' << std::endl;
        return 1;
    }
}

编辑:
正如@James T. Huggett 建议的那样, std::equal 更适合这个问题:A是B的前缀吗?并且代码略短:

std::equal(prefix.begin(), prefix.end(), toCheck.begin())

完整的示例程序:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char **argv) {
  if (argc != 3) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "Will print true if 'prefix' is a prefix of string"
              << std::endl;
    return -1;
  }
  std::string prefix(argv[1]);
  std::string toCheck(argv[2]);
  if (prefix.length() > toCheck.length()) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "'prefix' is longer than 'string'" << std::endl;
    return 2;
  }
  if (std::equal(prefix.begin(), prefix.end(), toCheck.begin())) {
    std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck
              << '"' << std::endl;
    return 0;
  } else {
    std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"'
              << toCheck << '"' << std::endl;
    return 1;
  }
}
Brice M. Dempsey 回复 1天 前

为什么不使用 std::equal?

matiu 回复 1天 前

听起来不错。它也将是更短的代码。我想,我现在必须编辑答案:p

Felix Dombek 回复 1天 前

使用std::equalfor strings 的缺点是它不会检测到字符串结尾,因此您需要手动检查前缀是否比整个字符串短。 (正如在示例 prog 中正确完成的那样,但在上面的单行中省略了。)

krab 回复 1天 前

和方法endsWith将会std::equal(suffix.rbegin(), suffix.rend(), toCheck.rbegin()