Dar*_*zer 213 c++ string parsing substring startswith
如何在C++中实现以下(Python伪代码)?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
Run Code Online (Sandbox Code Playgroud)
(例如,如果argv[1]是--foo=98,则foo_value是98.)
更新:我对调查Boost犹豫不决,因为我只是想对一个简单的小命令行工具进行一个非常小的改动(我宁愿不必学习如何链接并使用Boost作为一个小的更改).
Lud*_*ert 344
std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) {
// s starts with prefix
}
Run Code Online (Sandbox Code Playgroud)
谁还需要什么?纯STL!
Tho*_*mas 184
你会这样做:
std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
foo_value = atoi(arg.substr(prefix.size()).c_str());
Run Code Online (Sandbox Code Playgroud)
寻找像你这样做的Boost.ProgramOptions这样的lib也是一个好主意.
Fel*_*bek 141
为了完整起见,我将提到C方式:
如果
str是您的原始字符串,substr则是您要检查的子字符串
strncmp(str, substr, strlen(substr))
0如果str以...开头将返回substr.的功能strncmp和strlen在C头文件<string.h>
(原帖由拉乌夫·亚辛在这里,标记加)
对于不区分大小写的比较,请使用strnicmp而不是strncmp.
这是C方式,对于C++字符串,您可以使用相同的函数,如下所示:
strncmp(str.c_str(), substr.c_str(), substr.size())
Run Code Online (Sandbox Code Playgroud)
Fer*_*cio 84
如果你正在使用Boost,你可以使用boost字符串算法 + boost lexical cast:
#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
}
Run Code Online (Sandbox Code Playgroud)
像大多数boost库一样,字符串算法和词法转换只是标题,没有什么可以链接的.
像这里提供的许多其他答案一样,这种方法适用于非常简单的任务,但从长远来看,通常最好使用命令行解析库.Boost有一个(Boost.Program_options),如果您恰好使用Boost可能会有意义.
否则,搜索"c ++命令行解析器"将产生许多选项.
Hüs*_*ğlı 81
我自己使用的代码:
std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
std::string argumentValue = argument.substr(prefix.size());
}
Run Code Online (Sandbox Code Playgroud)
mat*_*tiu 46
还没有人使用过STL 算法/不匹配函数.如果返回true,则前缀是'toCheck'的前缀:
std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()
Run Code Online (Sandbox Code Playgroud)
完整示例编程:
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
正如@James T. Huggett所说,std :: equal更适合这个问题:A是B的前缀吗?并且是稍微短的代码:
std::equal(prefix.begin(), prefix.end(), toCheck.begin())
Run Code Online (Sandbox Code Playgroud)
完整示例编程:
#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;
}
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*tos 25
鉴于字符串 - argv[1]和"--foo"- 都是C字符串,@ FelixDombek的答案是最好的解决方案.
然而,看到其他答案,我认为值得注意的是,如果您的文本已经作为a提供std::string,那么存在一个迄今为止尚未提及的简单,零拷贝,最有效的解决方案:
const char * foo = "--foo";
if (text.rfind(foo, 0) == 0)
foo_value = text.substr(strlen(foo));
Run Code Online (Sandbox Code Playgroud)
如果foo已经是一个字符串:
std::string foo("--foo");
if (text.rfind(foo, 0) == 0)
foo_value = text.substr(foo.length());
Run Code Online (Sandbox Code Playgroud)
Gus*_*uss 15
std::string::starts_withhttps://en.cppreference.com/w/cpp/string/basic_string/starts_with
std::string str_value = /* smthg */;
const auto starts_with_foo = str_value.starts_with(std::string_view{"foo"});
Run Code Online (Sandbox Code Playgroud)
小智 11
使用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;
}
Run Code Online (Sandbox Code Playgroud)
Roi*_*ton 11
在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
}
Run Code Online (Sandbox Code Playgroud)
Tom*_*Tom 10
冒着使用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;
}
Run Code Online (Sandbox Code Playgroud)
下面是一些示例输出,它演示了解决方案处理前导/尾随垃圾与正确的Python代码一样正确,并且比使用的任何东西更准确atoi(错误地忽略非数字后缀).
$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number
Run Code Online (Sandbox Code Playgroud)
我使用std::string::compare包裹在下面的实用方法:
static bool startsWith(const string& s, const string& prefix) {
return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
Run Code Online (Sandbox Code Playgroud)
text.substr(0, start.length()) == start
Run Code Online (Sandbox Code Playgroud)
从 C++20 开始,您可以使用该starts_with方法。
std::string s = "abcd";
if (s.starts_with("abc")) {
...
}
Run Code Online (Sandbox Code Playgroud)
小智 7
在 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;
Run Code Online (Sandbox Code Playgroud)
所以你的代码可能是这样的:
std::string s{argv[1]};
if (s.starts_with("--foo="))
Run Code Online (Sandbox Code Playgroud)
如果您需要 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;
}
Run Code Online (Sandbox Code Playgroud)
为什么不使用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);
}
Run Code Online (Sandbox Code Playgroud)
对于以下命令:
$ ./a.out --foo=33
Run Code Online (Sandbox Code Playgroud)
你会得到
33
Run Code Online (Sandbox Code Playgroud)