¿Cómo implemento lo siguiente (pseudocódigo de Python) en C ++?
if argv[1].startswith('--foo='):
foo_value = int(argv[1][len('--foo='):])
(Por ejemplo, si argv[1]
es --foo=98
, entonces foo_value
es 98
).
Actualización: dudo en investigar Boost, ya que solo estoy buscando hacer un cambio muy pequeño en una pequeña herramienta de línea de comandos (preferiría no tener que aprender a vincular y usar Boost para un menor cambio).
Respuestas:
Utilice una sobrecarga de los
rfind
cuales tiene elpos
parámetro:¿Quién necesita algo más? STL puro!
Muchos han leído mal esto para significar "buscar hacia atrás en toda la cadena buscando el prefijo". Eso daría un resultado incorrecto (por ejemplo,
string("tititito").rfind("titi")
devuelve 2, por lo que, en comparación con== 0
, devolvería falso) y sería ineficiente (mirar a través de toda la cadena en lugar de solo el comienzo). Pero no lo hace porque pasa elpos
parámetro como0
, lo que limita la búsqueda para que solo coincida en esa posición o antes . Por ejemplo:fuente
find
solo será cero sititi
está al comienzo de la cadena. Si se encuentra en otro lugar, obtendrá un valor de retorno distinto de cero y, si no se encuentra, obtendrá un valornpos
que también sea distinto de cero. Suponiendo que tengo razón, preferiría esta respuesta ya que no tengo que traer ningún material no estándar (sí, sé que Boost está en todas partes, prefiero las bibliotecas centrales de C ++ para cosas simples como esta).titi
, pero falta la parte de conversión.rfind()
que no toma unpos
parámetro. Si usa la sobrecarga que toma unpos
parámetro, entonces no buscará toda la cadena, solo esa posición y antes. (Al igual que regularfind()
conpos
parámetro solo se ve en esa posición o más adelante). Entonces, si pasapos == 0
, como se muestra en esta respuesta, literalmente solo considerará las coincidencias en esa posición. Eso ya se explicaba tanto en la respuesta como en los comentarios.Lo harías así:
También es una buena idea buscar una biblioteca como Boost.ProgramOptions que haga esto por usted.
fuente
atoi("123xyz")
regresa123
, mientras que Pythonint("123xyz")
lanza una excepción.atoi
constrtol
ostrtoll
, lo que nos permite detectar condiciones de error en el valor de entrada.rfind
que depende de la optimización para funcionar.Solo para completar, mencionaré la forma C de hacerlo:
(publicado originalmente por Yaseen Rauf aquí , marcado agregado)
Para una comparación entre mayúsculas y minúsculas, use
strnicmp
lugar destrncmp
.Esta es la forma en C de hacerlo, para cadenas de C ++ puede usar la misma función como esta:
fuente
memcmp()
Si ya está utilizando Boost, puede hacerlo con algoritmos de cadena de impulso + lanzamiento léxico de impulso:
Este tipo de enfoque, como muchas de las otras respuestas proporcionadas aquí, está bien para tareas muy simples, pero a la larga generalmente es mejor usar una biblioteca de análisis de línea de comandos. Boost tiene uno ( Boost.Program_options ), que puede tener sentido si ya estás usando Boost.
De lo contrario, una búsqueda de "analizador de línea de comando c ++" arrojará una serie de opciones.
fuente
Código que uso yo mismo:
fuente
substr
conduce a copias innecesarias. Elstr.compare(start, count, substr)
método utilizado en la respuesta de Thomas es más eficiente. La respuesta de razvanco13 tiene otro método que evita la copia mediante el usostd::equal
.Thomas uses atoi which is only for windows
¿Eh?atoi
ha sido una función de biblioteca estándar C desde ... siempre. De hecho,atoi
es malo, no porque sea específico de Windows, sino porque es (1) C, no C ++, y (2) en desuso incluso en C (debe usarstrtol
una u otra de las funciones relacionadas. Porqueatoi
tiene sin manejo de errores. Pero, de nuevo, eso es solo en C, de todos modos).Nadie usó el STL función de algoritmo / desajuste todavía. Si esto devuelve verdadero, el prefijo es un prefijo de 'toCheck':
Programa completo de ejemplo:
Editar:
Como sugiere @James T. Huggett, std :: equal es una mejor opción para la pregunta: ¿Es A un prefijo de B? y es un código ligeramente más corto:
Programa completo de ejemplo:
fuente
std::equal
for strings tiene el inconveniente de que no detecta el final de la cadena, por lo que debe verificar manualmente si el prefijo es más corto que toda la cadena. (Como se hizo correctamente en el programa de ejemplo, pero se omitió en la línea de arriba.)Dado que ambas cadenas -
argv[1]
y"--foo"
- son cadenas C, la respuesta de @ FelixDombek la mejor solución.Sin embargo, al ver las otras respuestas, pensé que valía la pena señalar que, si su texto ya está disponible como un
std::string
, entonces existe una solución simple, de copia cero y máxima eficiencia que no se ha mencionado hasta ahora:Y si foo ya es una cadena:
fuente
rfind(x, 0) == 0
realmente debe ser definido en la norma comostarts_with
rfind()
(en lugar destartswith()
) es muy ineficiente: sigue buscando hasta el final de la cadena.Con C ++ 17 puede usar
std::basic_string_view
& con C ++ 20std::basic_string::starts_with
ostd::basic_string_view::starts_with
.El beneficio de,
std::string_view
en comparaciónstd::string
con la gestión de la memoria, es que solo contiene un puntero a una "cadena" (secuencia contigua de objetos tipo char) y conoce su tamaño. Ejemplo sin mover / copiar las cadenas de origen solo para obtener el valor entero:fuente
std::atoi
está completamente bien. Lanza excepciones en la entrada incorrecta (que se maneja en este código). ¿Tenías algo más en mente?atoi
de<cstdlib>
? La documentación dice "nunca arroja excepciones".atoi
lugar destd::atoi
. El primero no es seguro de usar, mientras que el segundo está bien. Estoy usando el último en el código aquí.std::atoi
efectivamente arroja una excepción, citando una referencia adecuada. Hasta que lo hagas, no te creo, ya que sería muy confuso tener ambos::atoi
ystd::atoi
actuar de una manera completamente diferente.std::atoi
se utilizó en lugar destd::stoi
. Ya lo arreglé.fuente
if (one-liner)
Usando STL esto podría verse así:
fuente
if (prefix.size()<=arg.size() && std::equal(...))
.A riesgo de ser criticado por usar construcciones en C, creo que este
sscanf
ejemplo es más elegante que la mayoría de las soluciones Boost. ¡Y no tiene que preocuparse por los enlaces si está ejecutando en cualquier lugar que tenga un intérprete de Python!Aquí hay algunos resultados de ejemplo que demuestran que la solución maneja la basura inicial / final tan correctamente como el código Python equivalente, y más correctamente que cualquier cosa que use
atoi
(que ignorará erróneamente un sufijo no numérico).fuente
argv[i]
es así"--foo=9999999999999999999999999"
, el comportamiento es indefinido (aunque la mayoría o todas las implementaciones deberían comportarse de manera sensata). Asumo9999999999999999999999999 > INT_MAX
.Yo uso
std::string::compare
envuelto en el método de utilidad como a continuación:fuente
¿Por qué no usar gnu getopts? Aquí hay un ejemplo básico (sin controles de seguridad):
Para el siguiente comando:
Conseguirás
fuente
En caso de que necesite compatibilidad con C ++ 11 y no pueda usar boost, aquí hay un complemento compatible con boost con un ejemplo de uso:
fuente
También puedes usar
strstr
:pero creo que es bueno solo para cadenas cortas porque tiene que recorrer toda la cadena cuando la cadena en realidad no comienza con 'substr'.
fuente
Ok, ¿por qué el uso complicado de bibliotecas y otras cosas? Los objetos de cadena de C ++ sobrecargan el operador [], por lo que puede comparar caracteres ... Como lo que acabo de hacer, porque quiero enumerar todos los archivos en un directorio e ignorar los archivos invisibles y ... y. pseudofiles.
Es así de simple..
fuente
fuente
Con C ++ 11 o superior puedes usar
find()
yfind_first_of()
Ejemplo usando find para encontrar un único carácter:
Ejemplo usando find para encontrar una cadena completa y comenzando desde la posición 5:
Ejemplo usando el
find_first_of()
y solo el primer carácter, para buscar solo al inicio:¡Buena suerte!
fuente
Dado que C ++ 11
std::regex_search
también se puede utilizar para proporcionar coincidencias de expresiones aún más complejas. El siguiente ejemplo maneja también números flotantes a través destd::stof
un lanzamiento posterior aint
.Sin embargo, el
parseInt
método que se muestra a continuación podría generar unastd::invalid_argument
excepción si el prefijo no coincide; esto se puede adaptar fácilmente según la aplicación dada:El tipo de magia del patrón regex está bien detallado en la siguiente respuesta .
EDITAR: la respuesta anterior no realizó la conversión a entero.
fuente
Comenzando con C ++ 20, puede usar el
starts_with
método.fuente
Esto no se ha probado por completo. El principio es el mismo que el de Python. Requiere Boost.StringAlgo y Boost.LexicalCast.
Verifique si la cadena comienza con la otra cadena, y luego obtenga la subcadena ('corte') de la primera cadena y conviértala usando el reparto léxico.
fuente