как проверить, начинается ли строка c ++ std :: string с определенной строки, и преобразовать подстроку в int?

<p>как мне реализовать следующее (псевдокод python) в c++?</p><pre><code>if argv[1].startswith('--foo='): foo\_value = int(argv[1][len('--foo='):]) </code></pre><p>(например, если <code>argv[1]</code> равен <code>--foo=98</code>, то <code>foo\_value</code> равен <code>98</code>.)</p><p><strong>pdate:</strong> мне не терпится заглянуть в boost, поскольку я просто смотрю на то, как внести небольшие изменения в простой маленький инструмент командной строки (мне бы не пришлось учиться связывать и используйте boost для незначительных изменений).</p>

<p>если вы уже используете boost, вы можете сделать это с помощью <a href="http://www.boost.org/doc/libs/1\_41\_0/doc/html/string\_algo.html">повысить алгоритмы строк</a> + <a href="http://www.boost.org/doc/libs/1\_41\_0/libs/conversion/lexical\_cast.htm">повысить лексическое приведение:</a> </p><pre><code>#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 } </code></pre><p>такой подход, как и многие другие ответы, представленные здесь, подходит для очень простых задач, но в долгосрочной перспективе обычно лучше использовать библиотеку синтаксического анализа командной строки. boost имеет один ( <a href="http://www.boost.org/doc/libs/1\_65\_1/doc/html/program\_options.html">boost.program\_options</a> ), что может иметь смысл, если вы уже используете boost.</p><p>в противном случае поиск "синтаксического анализатора командной строки c ++" даст ряд опций.</p>

<pre><code>std::string s = "tititoto"; if (s.rfind("titi", 0) == 0) { // s starts with prefix } </code></pre><p>кому еще что-нибудь нужно? чистый stl!</p>

<p>вы бы сделали это так:</p><pre><code>std::string prefix("--foo="); if (!arg.compare(0, prefix.size(), prefix)) foo\_value = atoi(arg.substr(prefix.size()).c\_str()); </code></pre><p>поиск библиотеки, такой как boost.programoptions, которая делает это для вас, также является хорошей идеей.</p>

<p>просто для полноты я упомяну способ c сделать это:</p><blockquote> <p>если <code>str</code> - ваша исходная строка, <code>substr</code> - подстрока, которую вы хотите проверить, тогда</p> <p><code>strncmp(str, substr, strlen(substr))</code></p> <p>вернет <code>0</code>, если <code>str</code> начинается с <code>substr</code>. функции <code>strncmp</code> и <code>strlen</code> находятся в заголовочном файле c <code><string.h></code></p> </blockquote><p><sup>(первоначально опубликовано yaseen rauf <a href="https://bytes.com/topic/c/answers/676092-how-do-we-check-whether-string-starts-substring#post3634983">здесь</a> , добавлена разметка)</sup></p><p>для сравнения без учета регистра используйте <code>strnicmp</code> вместо <code>strncmp</code>.</p><p>это способ c, для строк c++ вы можете использовать одну и ту же функцию следующим образом:</p><pre><code>strncmp(str.c\_str(), substr.c\_str(), substr.size()) </code></pre>

<p>код я использую сам:</p><pre><code>std::string prefix = "-param="; std::string argument = argv[1]; if(argument.substr(0, prefix.size()) == prefix) { std::string argumentvalue = argument.substr(prefix.size()); } </code></pre>

<p>никто еще не использовал функцию stl <a href="http://www.cplusplus.com/reference/algorithm/mismatch/">алгоритм/несоответствие</a> . если это возвращает true, префикс является префиксом 'tocheck':</p><pre><code>std::mismatch(prefix.begin(), prefix.end(), tocheck.begin()).first == prefix.end() </code></pre><p>полный пример проги:</p><pre><code>#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; } } </code></pre><hr><p><strong> edit: </strong></p><p>как предполагает @james t. huggett, std :: equal лучше подходит для вопроса: <em> является ли a префиксом b? </em> и немного короче:</p><pre><code>std::equal(prefix.begin(), prefix.end(), tocheck.begin()) </code></pre><p>полный пример проги:</p><pre><code>#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; } } </code></pre>

<p>учитывая, что обе строки - <code>argv[1]</code> и <code>"--foo"</code> - являются c-строками, <a href="https://stackoverflow.com/a/7142763/9990">ответ @ felixdombek</a> является лучшим решением, которое можно передать вручную.</p><p>однако, увидев другие ответы, я подумал, что стоит отметить, что если ваш текст уже доступен в виде <code>std::string</code>, то существует простое, максимально эффективное решение с нулевой копией, которое до сих пор не упоминалось:</p><pre><code>const char * foo = "--foo"; if (text.rfind(foo, 0) == 0) foo\_value = text.substr(strlen(foo)); </code></pre><p>и если foo уже является строкой:</p><pre><code>std::string foo("--foo"); if (text.rfind(foo, 0) == 0) foo\_value = text.substr(foo.length()); </code></pre>

<p>при использовании stl это может выглядеть так:</p><pre><code>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; } </code></pre>

<pre><code>text.substr(0, start.length()) == start </code></pre>

<p>с риском для того, чтобы быть воспламененным для использования конструкций c, я действительно думаю, что этот пример <code>sscanf</code> более элегантен, чем большинство решений boost. и вам не нужно беспокоиться о связях, если вы работаете в любом месте, где есть интерпретатор python!</p><pre><code>#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; } </code></pre><p>вот некоторые примеры выходных данных, которые демонстрируют, что решение обрабатывает начальный/конечный мусор так же правильно, как эквивалентный код python, и более правильно, чем что-либо другое, использующее <code>atoi</code> (которое будет ошибочно игнорировать нечисловой суффикс).</p><pre><code>$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2' number: 2 not-a-number not-a-number not-a-number 

с c++ 17 вы можете использовать <a href="http://en.cppreference.com/w/cpp/string/basic_string_view">std::basic_string_view & с c++ 20 <a href="http://en.cppreference.com/w/cpp/string/basic_string/starts_with">std::basic_string::starts_with или <a href="http://en.cppreference.com/w/cpp/string/basic_string_view/starts_with">std::basic_string_view::starts_with .преимущество std::string_view по сравнению с std::string - в отношении управления памятью - заключается в том, что он содержит только указатель на "строку" (непрерывную последовательность объектов, похожих на символы) и знает ее размер. пример без перемещения/копирования исходных строк только для получения целочисленного значения:#include <string_view> #include <exception> #include <iostream> const char  argument = "--foo=42"; // emulating command argument. const char  argumentprefix = "--foo"; int inputvalue = 0; std::string_view argview = argument; if (argview.starts_with(argumentprefix)) { std::string_view prefixview = argumentprefix; // helper for getting the size of argumentprefix. try { // the underlying data of argview is nul-terminated, therefore we can use data(). inputvalue = std::atoi(argview.substr(prefixview.size() + 1).data()); } catch (std::exception& e) { std::cerr << e.what(); } } 

я использую std::string::compare, завернутый в служебный метод, как показано ниже:static bool startswith(const string& s, const string& prefix) { return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0; } 

почему бы не использовать 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("%sn", optarg); } для следующей команды:$ ./a.out --foo=33 </code></pre><p>ты получишь</p><pre><code>33 </code></pre>

<p>в случае, если вам нужна совместимость с c++ 11 и вы не можете использовать boost, вот совместимое с boost усиление с примером использования:</p><pre><code>#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; } </code></pre>

<p>вы также можете использовать <code>strstr</code>:</p><pre><code>if (strstr(str, substr) == substr) { // 'str' starts with 'substr' } </code></pre><p>но я думаю, что это хорошо только для коротких строк, потому что он должен перебирать всю строку, когда строка на самом деле не начинается с 'substr'.</p>

<pre><code>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; } </code></pre>

<p>хорошо, почему сложное использование библиотек и прочего? строковые объекты c++ перегружают оператор [], поэтому вы можете просто сравнивать символы .. как и я, потому что я хочу перечислить все файлы в каталоге и игнорировать невидимые файлы и ... и. pseudofiles.</p><pre><code>while ((ep = readdir(dp))) { string s(ep->d\_name); if (!(s[0] == '.')) // omit invisible files and .. or . files.push\_back(s); } </code></pre><p>это так просто..</p>

<p>поскольку c++ 11 также можно использовать <a href="http://en.cppreference.com/w/cpp/regex/regex\_search">std :: regex\_search</a> , например, следующим образом (при ошибке возвращает пустую строку):</p><pre><code>#include <regex> std::string startswith(const std::string &str, const std::string &prefix) { std::smatch match; std::regex\_search(str, match, std::regex("^" + prefix)); return match.suffix(); } </code></pre>

<p>с c++ 11 или выше вы можете использовать <code>find()</code> и <code>find\_first\_of()</code></p><p>пример использования find для поиска одного символа:</p><pre><code>#include <string> std::string name = "aaah"; size\_t found\_index = name.find('a'); if (found\_index != std::string::npos) { // found string containing 'a' } </code></pre><p>пример использования find для поиска полной строки и начиная с позиции 5:</p><pre><code>std::string name = "aaah"; size\_t found\_index = name.find('h', 3); if (found\_index != std::string::npos) { // found string containing 'h' } </code></pre><p>пример использования <code>find\_first\_of()</code> и только первого символа для поиска только в начале:</p><pre><code>std::string name = ".hidden.\_di.r"; size\_t found\_index = name.find\_first\_of('.'); if (found\_index == 0) { // found '.' at first position in string } </code></pre><ul> <li> <a href="http://www.cplusplus.com/reference/string/string/find/">подробнее о поиске</a> </li> <li> <a href="http://www.cplusplus.com/reference/string/string/find\_first\_of/">подробнее о find\_first\_of</a> </li> </ul><p>удачи!</p>