如何检查C ++ <string>是否以某个string开始,并将一个子string转换为一个int?

如何在C ++中执行以下(Python伪代码)?

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

(例如,如果argv [1]是'–foo = 98',那么foo_value是98.)

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

使用booststringalgorithm + 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 } 

像大多数增强库一样,stringalgorithm和词法转换只是标题,没有什么可以链接的。

你会这样做:

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

寻找一个像Boost.ProgramOptions这样的库,这对你来说也是一个好主意。

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

如果str是你的原始string,那么substr就是你想要检查的子string

strncmp(str, substr, strlen(substr))

如果strsubstr开头,将返回0 。 函数strncmpstrlen在C头文件<string.h>

(最初由Yaseen Rauf 在这里发布,标记添加)

对于不区分大小写的比较,请使用strnicmp而不是strncmp

这是C的方式,对于C ++的string,你可以使用相同的函数:

 strncmp(str.c_str(), substr.c_str(), substr.size()) 

我自己使用的代码:

 std::string prefix = "-param="; std::string argument = argv[1]; if(argument.substr(0, prefix.size()) == prefix) { std::string argumentValue = argument.substr(prefix.size()); } 
 std::string s = "tititoto"; if (s.rfind("titi", 0) == 0) { // s starts with prefix } 

谁需要别的东西? 纯STL!

目前还没有人使用STL algorithm/失配函数。 如果返回true,则前缀是“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所build议的,std :: equal更适合这个问题: 是A的前缀吗? 并稍微短一点的代码:

 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; } } 

鉴于这两个string – argv[1]"--foo" – 是Cstring, @ FelixDombek的答案是最好的解决scheme。

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

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

如果foo已经是一个string:

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

冒着使用C构造的风险,我认为这个sscanf例子比大多数Boost解决scheme更优雅。 如果你正在任何有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; } 

下面是一些示例输出,演示了解决scheme如同对等Python代码一样正确处理前导/尾随垃圾,并且比使用atoi (会错误地忽略非数字后缀)的任何东西更正确。

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

使用STL这可能看起来像:

 std::string prefix = "--foo="; std::string arg = argv[1]; if (prefix.size()<=arg.size() && std::equal(prefix.begin(), prefix.end(), arg.begin())) { std::istringstream iss(arg.substr(prefix.size())); iss >> foo_value; } 

为什么不使用GNU getopts? 这是一个基本的例子(没有安全检查):

 #include <getopt.h> #include <stdio.h> int main(int argc, char** argv) { option long_options[] = { {"foo", required_argument, 0, 0}, {0,0,0,0} }; getopt_long(argc, argv, "f:", long_options, 0); printf("%s\n", optarg); } 

对于以下命令:

 $ ./a.out --foo=33 

你会得到

 33 

你也可以使用strstr

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

但我认为这只适用于短string,因为当string实际上并不是以'substr'开头的时候,它必须遍历整个string。

那么为什么复杂的使用库和东西? C ++string对象重载[]运算符,所以你可以比较字符。就像我刚刚做的,因为我想列出目录中的所有文件,并忽略不可见的文件和..和。 pseudofiles。

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

就这么简单

 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; } 
 if(boost::starts_with(string_to_search, string_to_look_for)) intval = boost::lexical_cast<int>(string_to_search.substr(string_to_look_for.length())); 

这完全没有经过testing。 原理和Python一样。 需要Boost.StringAlgo和Boost.LexicalCast。

检查string是否以另一个string开头,然后获取第一个string的子string('slice')并使用词法转换将其转换。