Как реализовать следующее (псевдокод Python) в C ++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Например, если argv[1]
есть --foo=98
, то foo_value
есть 98
.)
Обновление: я не решаюсь взглянуть на Boost, так как я просто смотрю на внесение очень небольших изменений в простой маленький инструмент командной строки (я бы предпочел не изучать, как подключаться и использовать Boost для незначительного изменение).
Ответы:
Используйте перегрузку
rfind
которого имеетpos
параметр:Кому еще что-нибудь нужно? Чистый STL!
Многие неверно истолковали это как «поиск по всей строке в поисках префикса». Это дало бы неправильный результат (например,
string("tititito").rfind("titi")
возвращает 2, поэтому при сравнении с== 0
вернуло бы false), и это было бы неэффективно (просмотр всей строки вместо только начала). Но он этого не делает, потому что передаетpos
параметр as0
, который ограничивает поиск совпадением только в этой позиции или ранее . Например:источник
find
будет нулевым, только если оноtiti
находится в начале строки. Если он найден где-то еще, вы получите ненулевое возвращаемое значение и, если он не найден, вы получитеnpos
также ненулевое значение. Предполагая, что я прав, я бы предпочел этот ответ, поскольку мне не нужно вводить какие-то нестандартные вещи (да, я знаю, что Boost везде, я бы просто предпочел базовые библиотеки C ++ для таких простых вещей, как этот).titi
, но часть преобразования отсутствует.rfind()
, которая не принимаетpos
параметр. Если вы используете перегрузку, которая принимаетpos
параметр, то он не будет искать всю строку, только эту позицию и ранее. (Так же, как обычныйfind()
сpos
параметром выглядит только в этой позиции или позже.) Так что, если вы передадитеpos == 0
, как показано в этом ответе, то он будет буквально рассматривать только для совпадений в этой одной позиции. Это уже объяснялось как в ответе, так и в комментариях.Вы бы сделали это так:
Поиск библиотеки, такой как Boost.ProgramOptions, которая делает это для вас, также является хорошей идеей.
источник
atoi("123xyz")
возврат123
, тогда как Pythonint("123xyz")
выдает исключение.atoi
наstrtol
илиstrtoll
, что позволяет нам определять условия ошибки во входном значении.rfind
которое зависит от оптимизации работы.Просто для полноты я упомяну способ C сделать это:
(первоначально размещено здесь Ясином Рауфом , добавлена разметка)
Для сравнения без учета регистра используйте
strnicmp
вместоstrncmp
.Это способ C, для строк C ++ вы можете использовать одну и ту же функцию следующим образом:
источник
memcmp()
Если вы уже используете Boost, вы можете сделать это с помощью алгоритмов boost string + boost lexical cast:
Такой подход, как и многие другие ответы, представленные здесь, подходит для очень простых задач, но в долгосрочной перспективе обычно лучше использовать библиотеку синтаксического анализа командной строки. Boost имеет один ( Boost.Program_options ), который может иметь смысл, если вы уже используете Boost.
В противном случае поиск «синтаксического анализатора командной строки c ++» даст ряд опций.
источник
Код я использую сам:
источник
substr
приводит к ненужному копированию.str.compare(start, count, substr)
Метод , используемый в ответ Томаса является более эффективным. Ответ Razvanco13 имеет другой метод, который позволяет избежать копирования с помощьюstd::equal
.Thomas uses atoi which is only for windows
?atoi
была стандартной библиотечной функцией C с тех пор ... В самом деле,atoi
это bad- не потому , что Windows , specific- а потому , что (1) C, а не C ++, и (2) не рекомендуется даже в C (вы должны использоватьstrtol
или один из других, связанных с ними функций. Так какatoi
есть нет обработки ошибок. Но, опять же, это только в C, в любом случае).Никто еще не использовал алгоритм STL / функцию несовпадения . Если это возвращает true, префикс является префиксом 'toCheck':
Полный пример проги:
Редактировать:
Как предполагает @James T. Huggett, std :: equal лучше подходит для вопроса: является ли A префиксом B? и немного короче код:
Полный пример проги:
источник
std::equal
Недостатком использования for strings является то, что он не определяет конец строки, поэтому вам нужно вручную проверить, не короче ли префикс, чем вся строка. (Как правильно сделано в примере с прогой, но опущено в однострочнике выше.)Учитывая, что обе строки -
argv[1]
и"--foo"
- являются C-строками, ответ @ FelixDombek - лучшее решение , сделанное на практике .Однако, увидев другие ответы, я подумал, что стоит отметить, что если ваш текст уже доступен как
std::string
, то существует простое, максимально эффективное решение, которое до сих пор не упоминалось:И если foo уже является строкой:
источник
rfind(x, 0) == 0
действительно должно быть определено в стандарте какstarts_with
rfind()
(вместоstartswith()
) очень неэффективно - поиск продолжается до конца строки.С C ++ 17 вы можете использовать
std::basic_string_view
& с C ++ 20std::basic_string::starts_with
илиstd::basic_string_view::starts_with
.Преимущество по
std::string_view
сравнению сstd::string
управлением памятью состоит в том, что оно содержит только указатель на «строку» (непрерывную последовательность объектов, похожих на символы) и знает ее размер. Пример без перемещения / копирования исходных строк только для получения целочисленного значения:источник
std::atoi
все в порядке. Он генерирует исключения при неправильном вводе (который обрабатывается в этом коде). Вы имели в виду что-то еще?atoi
от<cstdlib>
? Документация говорит «она никогда не вызывает исключения».atoi
вместоstd::atoi
. Первый небезопасен в использовании, а второй в порядке. Я использую последнее в коде здесь.std::atoi
действительно выдает исключение, цитируя подходящую ссылку. Пока вы этого не сделаете, я вам не верю, так как было бы очень запутанно иметь и то,::atoi
и другое,std::atoi
действовать совершенно иначе.std::atoi
использовалось вместоstd::stoi
. Я исправил это.источник
if (one-liner)
При использовании STL это может выглядеть так:
источник
if (prefix.size()<=arg.size() && std::equal(...))
.Я думаю, что этот риск
sscanf
более изящен, чем большинство решений Boost, и рискует оказаться под угрозой . И вам не нужно беспокоиться о связях, если вы работаете в любом месте, где есть интерпретатор Python!Вот некоторые примеры выходных данных, которые демонстрируют, что решение обрабатывает начальный / конечный мусор так же правильно, как и эквивалентный код Python, и более правильно, чем что-либо использующее
atoi
(которое будет ошибочно игнорировать нечисловой суффикс).источник
argv[i]
есть"--foo=9999999999999999999999999"
, поведение не определено (хотя большинство или все реализации должны вести себя разумно). Я предполагаю9999999999999999999999999 > INT_MAX
.Я использую
std::string::compare
упакованный в утилиту метод, как показано ниже:источник
Почему бы не использовать GNU Getopts? Вот базовый пример (без проверок безопасности):
Для следующей команды:
Ты получишь
источник
В случае, если вам нужна совместимость с C ++ 11 и вы не можете использовать boost, вот совместимое с boost усиление с примером использования:
источник
Вы также можете использовать
strstr
:но я думаю, что это хорошо только для коротких строк, потому что он должен перебирать всю строку, когда строка на самом деле не начинается с 'substr'.
источник
Хорошо, почему сложное использование библиотек и прочего? Строковые объекты C ++ перегружают оператор [], так что вы можете просто сравнивать символы .. Как и я, потому что я хочу перечислить все файлы в каталоге и игнорировать невидимые файлы и ... и. pseudofiles.
Это так просто..
источник
источник
С C ++ 11 или выше вы можете использовать
find()
иfind_first_of()
Пример использования find для поиска одного символа:
Пример использования find для поиска полной строки и начиная с позиции 5:
Пример использования
find_first_of()
только и только первого символа для поиска только в начале:Удачи!
источник
Поскольку C ++ 11
std::regex_search
также может использоваться для обеспечения еще более сложного соответствия выражений. Следующий пример обрабатывает также плавающие числаstd::stof
и последующее приведение кint
.Однако
parseInt
метод, показанный ниже, может вызватьstd::invalid_argument
исключение, если префикс не совпадает; это может быть легко адаптировано в зависимости от данного приложения:Вид магии паттерна регулярных выражений хорошо описан в следующем ответе .
РЕДАКТИРОВАТЬ: предыдущий ответ не выполнил преобразование в целое число.
источник
Начиная с C ++ 20, вы можете использовать
starts_with
метод.источник
Это полностью не проверено. Принцип такой же, как у Python. Требуются Boost.StringAlgo и Boost.LexicalCast.
Проверьте, начинается ли строка с другой строки, а затем получите подстроку ('slice') первой строки и преобразуйте ее, используя лексическое приведение.
источник