Как проверить, начинается ли C++ std :: string с определенной строки, и преобразовать подстроку в int?
Как мне реализовать следующее (псевдокод Python) в C++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Например, если argv[1]
равно --foo=98
, тогда foo_value
равно 98
)
Обновление: я не решаюсь взглянуть на Boost, так как я просто смотрю на внесение очень небольших изменений в простой маленький инструмент командной строки (я бы предпочел не изучать, как связать и использовать Boost для незначительного менять).
Ответы
Ответ 1
Если вы уже используете Boost, вы можете сделать это с помощью алгоритмов boost string + 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
}
Такой подход, как и многие другие ответы, представленные здесь, подходит для очень простых задач, но в долгосрочной перспективе обычно лучше использовать библиотеку синтаксического анализа командной строки. Boost имеет один (Boost.Program_options), который может иметь смысл, если вы уже используете Boost.
В противном случае поиск "синтаксического анализатора командной строки c++" даст ряд опций.
Ответ 2
Используйте перегрузку rfind
с параметром pos
. Здесь pos
является последним индексом, который будет считаться частью предмета поиска (поэтому, если ваша строка будет titititi
, последняя titi
не будет рассматриваться, поскольку она начинается позже, чем выбранный pos=0
):
std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) {
// s starts with prefix
}
Кому еще что-нибудь нужно? Чистый STL!
Ответ 3
Вы бы сделали это так:
std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
foo_value = atoi(arg.substr(prefix.size()).c_str());
Поиск библиотеки, такой как Boost.ProgramOptions, которая делает это для вас, также является хорошей идеей.
Ответ 4
Просто для полноты я упомяну способ C сделать это:
Если str
- ваша исходная строка, substr
- подстрока, которую вы хотите проверить, тогда
strncmp(str, substr, strlen(substr))
вернет 0
если str
начинается с substr
. Функции strncmp
и strlen
находятся в заголовочном файле C <string.h>
(первоначально размещено здесь Ясином Рауфом, добавлена разметка)
Для сравнения без strnicmp
регистра используйте strnicmp
вместо strncmp
.
Это способ C сделать это, для строк C++ вы можете использовать ту же функцию, например:
strncmp(str.c_str(), substr.c_str(), substr.size())
Ответ 5
Код, который я использую сам:
std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
std::string argumentValue = argument.substr(prefix.size());
}
Ответ 6
Никто еще не использовал функцию STL algorithm/mismatch. Если это возвращает 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;
}
}
Edit:
Как говорит @James T. Huggett, std:: equal лучше подходит для вопроса: является ли префиксом 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;
}
}
Ответ 7
Учитывая, что обе строки - argv[1]
и "--foo"
- являются строками C, @FelixDombek answer - лучшее решение.
Однако, учитывая другие ответы, я подумал, что стоит отметить, что если ваш текст уже доступен как 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());
Ответ 8
Использование 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;
}
Ответ 9
Из-за риска пламени для использования конструкций 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;
}
Вот пример вывода, который демонстрирует, что решение обрабатывает ведущий/конечный мусор так же корректно, как эквивалентный код Python, и более корректно, чем что-либо, используя atoi
(который ошибочно игнорирует нечисловой суффикс).
$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number
Ответ 10
Я использую std::string::compare
в служебном методе, как показано ниже:
static bool startsWith(const string& s, const string& prefix) {
return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
Ответ 11
text.substr(0, start.length()) == start
Ответ 12
С С++ 17 вы можете использовать std::basic_string_view
& с С++ 20 std::basic_string::starts_with
или std::basic_string_view::starts_with
.
Преимущество std::string_view
по сравнению с std::string
- в отношении управления памятью - заключается в том, что он содержит только указатель на "строку" (непрерывную последовательность символов, подобных символу) и знает ее размер. Пример без перемещения/копирования исходных строк только для получения целочисленного значения:
#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
}
Ответ 13
Почему бы не использовать 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
Ответ 14
В случае, если вам нужна совместимость с С++ 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;
}
Ответ 15
Хорошо, почему сложное использование библиотек и прочего? C++ Строковые объекты перегружают оператор [], так что вы можете просто сравнивать символы.. Как и то, что я только что сделал, потому что я хочу перечислить все файлы в каталоге и игнорировать невидимые файлы и... и. pseudofiles.
while ((ep = readdir(dp)))
{
string s(ep->d_name);
if (!(s[0] == '.')) // Omit invisible files and .. or .
files.push_back(s);
}
Это так просто..
Ответ 16
Вы также можете использовать strstr
:
if (strstr(str, substr) == substr) {
// 'str' starts with 'substr'
}
но я думаю, что это хорошо только для коротких строк, потому что он должен перебирать всю строку, когда строка фактически не начинается с 'substr'.
Ответ 17
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;
}
Ответ 18
хотя я опаздываю на вечеринку на 8 лет, вот простейший способ сделать это:
#include <iostream>
#include <string>
using namespace std; // for clarity sake.
bool startswith(string prefix, string text) {
if (prefix.length() > 0 && text.length() > prefix.length()) {
int i = 0;
while (i < prefix.length()) {
if (text[i] != prefix[i]) return false;
i++;
}
return true;
}
else return false;
}
int main (int argc, char* argv) {
if(startswith("--foo=", argv[1]))
// do something about it!
}
Ответ 19
Поскольку в С++ 11 также можно использовать std :: regex_search, например, следующим образом (при ошибке возвращает пустую строку):
#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();
}
Ответ 20
С С++ 11 или выше вы можете использовать find()
и find_first_of()
Пример использования find для поиска одного символа:
#include <string>
std::string name = "Aaah";
size_t found_index = name.find('a');
if (found_index != std::string::npos) {
// Found string containing 'a'
}
Пример использования find для поиска полной строки и начиная с позиции 5:
std::string name = "Aaah";
size_t found_index = name.find('h', 3);
if (found_index != std::string::npos) {
// Found string containing 'h'
}
Пример использования find_first_of()
и только первого символа для поиска только в начале:
std::string name = ".hidden._di.r";
size_t found_index = name.find_first_of('.');
if (found_index == 0) {
// Found '.' at first position in string
}
Удачи!
Ответ 21
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()));
Это полностью непроверено. Принцип такой же, как и Python. Требуется Boost.StringAlgo и Boost.LexicalCast.
Проверить, начинается ли строка с другой строкой, а затем получить подстроку ('slice') первой строки и преобразовать ее с помощью лексического перевода.