Como implementar o seguinte (pseudocódigo Python) em C ++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Por exemplo, se argv[1]
for --foo=98
, então foo_value
é 98
.)
Atualização: hesito em analisar o Boost, já que estou apenas tentando fazer uma alteração muito pequena em uma ferramenta simples de linha de comando (prefiro não precisar aprender como vincular e usar o Boost por um período menor) mudança).
Respostas:
Use uma sobrecarga
rfind
com opos
parâmetro:Quem precisa de mais alguma coisa? STL puro!
Muitos interpretaram erroneamente que isso significa "pesquisar para trás por toda a cadeia de caracteres procurando o prefixo". Isso daria o resultado errado (por exemplo,
string("tititito").rfind("titi")
retorna 2 e, quando comparado== 0
, retornaria false) e seria ineficiente (examinar toda a cadeia de caracteres em vez de apenas o início). Mas isso não ocorre porque passa opos
parâmetro como0
, o que limita a pesquisa a corresponder apenas nessa posição ou anteriormente . Por exemplo:fonte
find
somente será zero setiti
estiver no início da string. Se for encontrado em outro lugar, você obterá um valor de retorno diferente de zero e, se não for encontrado, receberánpos
também um valor diferente de zero. Supondo que estou certo, eu preferiria esta resposta, já que não tenho que trazer nada fora do padrão (sim, eu sei que o Boost está em todo lugar, eu preferiria as principais bibliotecas C ++ para coisas simples como essa).titi
, mas a parte de conversão está faltando.rfind()
que não requer umpos
parâmetro. Se você usar a sobrecarga que aceita umpos
parâmetro, ela não pesquisará toda a cadeia, apenas essa posição e a anterior. (Assim como regular,find()
com opos
parâmetro apenas aparece nessa posição ou mais tarde.) Portanto, se você passarpos == 0
, como mostrado nesta resposta, ele literalmente considerará apenas as correspondências nessa posição. Isso já estava explicando tanto na resposta quanto nos comentários.Você faria assim:
Procurar uma biblioteca como o Boost.ProgramOptions que faça isso por você também é uma boa ideia.
fonte
atoi("123xyz")
retorno123
, enquanto o Pythonint("123xyz")
lança uma exceção.atoi
porstrtol
oustrtoll
, o que nos permite detectar condições de erro no valor de entrada.rfind
aquela que depende da otimização para funcionar.Apenas para completar, vou mencionar a maneira C de fazê-lo:
(originalmente publicado por Yaseen Rauf aqui , marcação adicionada)
Para uma comparação que não diferencia maiúsculas de minúsculas, use em
strnicmp
vez destrncmp
.Esta é a maneira C de fazer isso, para cadeias de caracteres C ++ você pode usar a mesma função como esta:
fonte
memcmp()
Se você já está usando o Boost, pode fazê-lo com algoritmos de sequência de impulso + elenco lexical de aumento:
Esse tipo de abordagem, como muitas das outras respostas fornecidas aqui, é aceitável para tarefas muito simples, mas a longo prazo, geralmente é melhor usar uma biblioteca de análise de linha de comando. O Boost possui um ( Boost.Program_options ), que pode fazer sentido se você já estiver usando o Boost.
Caso contrário, uma pesquisa por "analisador de linha de comando c ++" produzirá várias opções.
fonte
Código que eu me uso:
fonte
substr
leva a cópias desnecessárias. Ostr.compare(start, count, substr)
método usado na resposta de Thomas é mais eficiente. A resposta de razvanco13 possui outro método que evita a cópia usandostd::equal
.Thomas uses atoi which is only for windows
Huh?atoi
tem sido uma função de biblioteca padrão C desde ... sempre. Na verdade,atoi
é ruim- não porque do Windows specific- mas porque é (1) C, não C ++, e (2) obsoleto mesmo em C (você deve estar usandostrtol
ou uma das outras funções, relacionadas. Porqueatoi
tem sem tratamento de erros, mas, novamente, isso é apenas em C).Ninguém usou ainda a função de algoritmo / incompatibilidade STL . Se isso retornar verdadeiro, o prefixo será o prefixo 'toCheck':
Exemplo completo prog:
Editar:
Como @ James T. Huggett sugere, std :: equal é mais adequado para a pergunta: A é um prefixo de B? e é um código ligeiramente mais curto:
Exemplo completo prog:
fonte
std::equal
de strings tem o lado negativo de não detectar o final da string, portanto, é necessário verificar manualmente se o prefixo é mais curto que a string inteira. (Como corretamente feito no exemplo prog, mas omitido no one-liner acima.)Dado que ambas as strings -
argv[1]
e"--foo"
- são C, a resposta de @ FelixDombek a melhor solução.No entanto, vendo as outras respostas, achei interessante notar que, se o seu texto já estiver disponível como uma
std::string
, existe uma solução simples, de cópia zero e maximamente eficiente, que não foi mencionada até agora:E se foo já é uma string:
fonte
rfind(x, 0) == 0
realmente deve ser definido no padrão comostarts_with
rfind()
(no lugar destartswith()
) é muito ineficiente - ele continua pesquisando até o final da string.Com o C ++ 17, você pode usar
std::basic_string_view
e com o C ++ 20std::basic_string::starts_with
oustd::basic_string_view::starts_with
.O benefício de,
std::string_view
em comparação comstd::string
- no gerenciamento de memória -, é que ele mantém apenas um ponteiro para uma "string" (sequência contígua de objetos do tipo char) e conhece seu tamanho. Exemplo sem mover / copiar as strings de origem apenas para obter o valor inteiro:fonte
std::atoi
está completamente bem. Ele lança exceções na entrada incorreta (que é tratada neste código). Você tinha outra coisa em mente?atoi
de<cstdlib>
? A documentação diz "nunca lança exceções".atoi
vez destd::atoi
. O primeiro não é seguro, enquanto o último é bom. Estou usando o último no código aqui.std::atoi
realmente lança uma exceção, citando uma referência adequada. Até você acreditar, eu não acredito em você, pois seria muito confuso ter os dois::atoi
estd::atoi
agir de uma maneira completamente diferente.std::atoi
foi usada em vez destd::stoi
. Eu consertei isso.fonte
if (one-liner)
Usando STL, isso pode se parecer com:
fonte
if (prefix.size()<=arg.size() && std::equal(...))
.Correndo o risco de ser queimado por usar construções C, acho que este
sscanf
exemplo é mais elegante do que a maioria das soluções Boost. E você não precisa se preocupar com o vínculo se estiver executando em qualquer lugar que tenha um intérprete Python!Aqui está um exemplo de saída que demonstra que a solução lida com o lixo inicial / final tão corretamente quanto o código Python equivalente e mais corretamente do que qualquer coisa usando
atoi
(o que ignorará erroneamente um sufixo não numérico).fonte
argv[i]
for"--foo=9999999999999999999999999"
, o comportamento é indefinido (embora a maioria ou todas as implementações devam se comportar de maneira saudável). Estou assumindo9999999999999999999999999 > INT_MAX
.Eu uso
std::string::compare
embrulhado no método utilitário como abaixo:fonte
Por que não usar gnu getopts? Aqui está um exemplo básico (sem verificações de segurança):
Para o seguinte comando:
Você vai ter
fonte
Caso você precise de compatibilidade com C ++ 11 e não possa usar o boost, aqui está um drop-in compatível com o boost com um exemplo de uso:
fonte
Você também pode usar
strstr
:mas acho que é bom apenas para cadeias curtas, porque precisa percorrer toda a cadeia quando a cadeia não começa realmente com 'substr'.
fonte
Ok, por que o uso complicado de bibliotecas e outras coisas? Os objetos String C ++ sobrecarregam o operador [], para que você possa comparar os caracteres .. Como o que acabei de fazer, porque quero listar todos os arquivos em um diretório e ignorar os arquivos invisíveis e os .. e. pseudofiles.
É simples assim..
fonte
fonte
Com o C ++ 11 ou superior, você pode usar
find()
efind_first_of()
Exemplo usando find para encontrar um único caractere:
Exemplo usando find para encontrar uma string completa e começando na posição 5:
Exemplo usando o
find_first_of()
e apenas o primeiro caractere, para pesquisar apenas no início:Boa sorte!
fonte
Como o C ++ 11
std::regex_search
também pode ser usado para fornecer correspondência de expressões ainda mais complexas. O exemplo a seguir também lida com números flutuantes thorughstd::stof
e uma conversão subsequente paraint
.No entanto, o
parseInt
método mostrado abaixo pode gerar umastd::invalid_argument
exceção se o prefixo não for correspondido; isso pode ser facilmente adaptado, dependendo da aplicação fornecida:O tipo de mágica do padrão regex é bem detalhado na resposta a seguir .
EDIT: a resposta anterior não realizou a conversão para número inteiro.
fonte
Começando com C ++ 20, você pode usar o
starts_with
métodofonte
Isso é completamente não testado. O princípio é o mesmo que o Python. Requer Boost.StringAlgo e Boost.LexicalCast.
Verifique se a sequência começa com a outra e, em seguida, obtenha a substring ('fatia') da primeira e converta-a usando conversão lexical.
fonte