Estoy tratando de escribir un programa que pueda comparar dos archivos línea por línea, palabra por palabra o carácter por carácter en C. Tiene que poder leer en las opciones de la línea de comandos -l -w -i or --
...
- si la opción es -l, compara los archivos línea por línea.
- si la opción es -w, compara los archivos palabra por palabra.
- si la opción es, automáticamente asume que el siguiente argumento es el primer nombre de archivo.
- si la opción es -i, los compara sin diferenciar entre mayúsculas y minúsculas.
- por defecto compara los archivos carácter a carácter.
No se supone que importe cuántas veces se ingresan las opciones siempre que -w y -l no se ingresen al mismo tiempo y no haya más o menos de 2 archivos.
Ni siquiera sé por dónde empezar a analizar los argumentos de la línea de comandos. POR FAVOR AYUDA :(
Así que este es el código que se me ocurrió para todo. Todavía no he comprobado el error, pero me preguntaba si estoy escribiendo cosas de una manera demasiado complicada.
/*
* Functions to compare files.
*/
int compare_line();
int compare_word();
int compare_char();
int case_insens();
/*
* Program to compare the information in two files and print message saying
* whether or not this was successful.
*/
int main(int argc, char* argv[])
{
/*Loop counter*/
size_t i = 0;
/*Variables for functions*/
int caseIns = 0;
int line = 0;
int word = 0;
/*File pointers*/
FILE *fp1, *fp2;
/*
* Read through command-line arguments for options.
*/
for (i = 1; i < argc; i++) {
printf("argv[%u] = %s\n", i, argv[i]);
if (argv[i][0] == '-') {
if (argv[i][1] == 'i')
{
caseIns = 1;
}
if (argv[i][1] == 'l')
{
line = 1;
}
if (argv[i][1] == 'w')
{
word = 1;
}
if (argv[i][1] == '-')
{
fp1 = argv[i][2];
fp2 = argv[i][3];
}
else
{
printf("Invalid option.");
return 2;
}
} else {
fp1(argv[i]);
fp2(argv[i][1]);
}
}
/*
* Check that files can be opened.
*/
if(((fp1 = fopen(fp1, "rb")) == NULL) || ((fp2 = fopen(fp2, "rb")) == NULL))
{
perror("fopen()");
return 3;
}
else{
if (caseIns == 1)
{
if(line == 1 && word == 1)
{
printf("That is invalid.");
return 2;
}
if(line == 1 && word == 0)
{
if(compare_line(case_insens(fp1, fp2)) == 0)
return 0;
}
if(line == 0 && word == 1)
{
if(compare_word(case_insens(fp1, fp2)) == 0)
return 0;
}
else
{
if(compare_char(case_insens(fp1,fp2)) == 0)
return 0;
}
}
else
{
if(line == 1 && word == 1)
{
printf("That is invalid.");
return 2;
}
if(line == 1 && word == 0)
{
if(compare_line(fp1, fp2) == 0)
return 0;
}
if(line == 0 && word == 1)
{
if(compare_word(fp1, fp2) == 0)
return 0;
}
else
{
if(compare_char(fp1, fp2) == 0)
return 0;
}
}
}
return 1;
if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL)))
{
perror("fclose()");
return 3;
}
else
{
fp1 = fclose(fp1);
fp2 = fclose(fp2);
}
}
/*
* Function to compare two files line-by-line.
*/
int compare_line(FILE *fp1, FILE *fp2)
{
/*Buffer variables to store the lines in the file*/
char buff1 [LINESIZE];
char buff2 [LINESIZE];
/*Check that neither is the end of file*/
while((!feof(fp1)) && (!feof(fp2)))
{
/*Go through files line by line*/
fgets(buff1, LINESIZE, fp1);
fgets(buff2, LINESIZE, fp2);
}
/*Compare files line by line*/
if(strcmp(buff1, buff2) == 0)
{
printf("Files are equal.\n");
return 0;
}
printf("Files are not equal.\n");
return 1;
}
/*
* Function to compare two files word-by-word.
*/
int compare_word(FILE *fp1, FILE *fp2)
{
/*File pointers*/
FILE *fp1, *fp2;
/*Arrays to store words*/
char fp1words[LINESIZE];
char fp2words[LINESIZE];
if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL)
{
printf("File is empty. Cannot compare.\n");
return 0;
}
else
{
fp1words = strtok(fp1, " ");
fp2words = strtok(fp2, " ");
if(fp1words == fp2words)
{
fputs(fp1words);
fputs(fp2words);
printf("Files are equal.\n");
return 0;
}
}
return 1;
}
/*
* Function to compare two files character by character.
*/
int compare_char(FILE *fp1,FILE *fp2)
{
/*Variables to store the characters from both files*/
int c;
int d;
/*Buffer variables to store chars*/
char buff1 [LINESIZE];
char buff2 [LINESIZE];
while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF)))
{
if(c == d)
{
if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2)))
{
printf("Files have equivalent characters.\n");
return 1;
break;
}
}
}
return 0;
}
/*
* Function to compare two files in a case-insensitive manner.
*/
int case_insens(FILE *fp1, FILE *fp2, size_t n)
{
/*Pointers for files.*/
FILE *fp1, *fp2;
/*Variable to go through files.*/
size_t i = 0;
/*Arrays to store file information.*/
char fp1store[LINESIZE];
char fp2store[LINESIZE];
while(!feof(fp1) && !feof(fp2))
{
for(i = 0; i < n; i++)
{
fscanf(fp1, "%s", fp1store);
fscanf(fp2, "%s", fp2store);
fp1store = tolower(fp1store);
fp2store = tolower(fp2store);
return 1;
}
}
return 0;
}
c
command-line-arguments
usuario1251020
fuente
fuente
Respuestas:
Que yo sepa, las tres formas más populares de analizar los argumentos de la línea de comandos en C son:
#include <unistd.h>
de la biblioteca POSIX C), que puede resolver tareas simples de análisis de argumentos . Si está un poco familiarizado con bash, el getopt incorporado de bash se basa en Getopt de la libc de GNU.#include <argp.h>
de la biblioteca GNU C), que puede resolver tareas más complejas y se ocupa de cosas como, por ejemplo:-?
,--help
para recibir mensajes de ayuda , incluida la dirección de correo electrónico-V
,--version
para obtener información sobre la versión--usage
para mensaje de usoLa documentación de la biblioteca GNU C tiene algunos buenos ejemplos para Getopt y Argp.
Ejemplo de uso de Getopt
Ejemplo para usar Argp
Ejemplo para hacerlo usted mismo
Descargo de responsabilidad: soy nuevo en Argp, el ejemplo puede contener errores.
fuente
Utilice
getopt()
, o quizásgetopt_long()
.Tenga en cuenta que debe determinar qué encabezados incluir (lo hago 4 que son obligatorios), y la forma en que escribí el
op_mode
tipo significa que tiene un problema en la funciónprocess()
: no puede acceder a la enumeración allí. Es mejor mover la enumeración fuera de la función; incluso podría crearop_mode
una variable de alcance de archivo sin vinculación externa (una forma elegante de decirlostatic
) para evitar pasarla a la función. Este código no se maneja-
como sinónimo de entrada estándar, otro ejercicio para el lector. Tenga en cuenta quegetopt()
automáticamente se encarga de--
marcar el final de las opciones por usted.No he ejecutado ninguna versión de la escritura anterior más allá de un compilador; podría haber errores en él.
Para obtener crédito adicional, escriba una función (biblioteca):
que encapsula la lógica para procesar las opciones de nombre de archivo después del
getopt()
ciclo. Debe manejarse-
como entrada estándar. Tenga en cuenta que usar esto indicaría queop_mode
debería ser una variable de alcance de archivo estático. Lafilter()
función tomaargc
,argv
,optind
y un puntero a la función de procesamiento. Debería devolver 0 (EXIT_SUCCESS) si pudo abrir todos los archivos y todas las invocaciones de la función reportadas 0, de lo contrario 1 (o EXIT_FAILURE). Tener una función de este tipo simplifica la escritura de programas de 'filtro' estilo Unix que leen archivos especificados en la línea de comando o en la entrada estándar.fuente
getopt()
no lo hace; GNU logetopt()
hace por defecto. Elige tu opción. No estoy interesado en las opciones después del comportamiento de los nombres de archivo, principalmente porque no es confiable en todas las plataformas.Encontré que Gengetopt es bastante útil: usted especifica las opciones que desea con un archivo de configuración simple y genera un par .c / .h que simplemente incluye y vincula con su aplicación. El código generado hace uso de getopt_long, parece manejar los tipos más comunes de parámetros de línea de comando y puede ahorrar mucho tiempo.
Un archivo de entrada de gengetopt podría verse así:
Generar el código es fácil y escupe
cmdline.h
ycmdline.c
:El código generado se integra fácilmente:
Si necesita hacer alguna verificación adicional (como asegurarse de que los indicadores sean mutuamente excluyentes), puede hacerlo con bastante facilidad con los datos almacenados en la
gengetopt_args_info
estructura.fuente
#include
, no en el archivo generado en sí. para mí, apagar las advertencias está prohibido :-)Estoy muy sorprendido de que nadie haya mencionado el paquete "opt" de James Theiler.
Puede encontrar optar en http://public.lanl.gov/jt/Software/
y una publicación halagadora con algunos ejemplos de cómo es mucho más simple que otros enfoques está aquí:
http://www.decompile.com/not_invented_here/opt/
fuente
Docopt tiene una implementación de C que pensé que era bastante buena: https://github.com/docopt/docopt.c
A partir de un formato estandarizado de página de manual que describe las opciones de la línea de comandos, docopt infiere y crea un analizador de argumentos. Esto comenzó en Python; la versión de Python literalmente simplemente analiza la cadena de documentos y devuelve un dict. Hacer esto en C requiere un poco más de trabajo, pero es limpio de usar y no tiene dependencias externas.
fuente
Hay una gran biblioteca de C de propósito general libUCW que incluye un ordenado análisis de opciones de línea de comandos y carga de archivos de configuración .
La biblioteca también viene con buena documentación e incluye algunas otras cosas útiles (E / S rápidas, estructuras de datos, asignadores, ...) pero esto se puede usar por separado.
Ejemplo de analizador de opciones libUCW (de los documentos de la biblioteca)
fuente
Escribí una pequeña biblioteca que analiza argumentos similares a POpt, con los que tuve varios problemas, llamada XOpt . Utiliza análisis de argumentos al estilo GNU y tiene una interfaz muy similar a POpt.
Lo uso de vez en cuando con gran éxito y funciona prácticamente en cualquier lugar.
fuente
Tocando mi propio cuerno si puedo, también me gustaría sugerir que eche un vistazo a una biblioteca de análisis de opciones que he escrito: dropt .
Una característica que ofrece y que muchos otros no ofrecen es la capacidad de anular opciones anteriores. Por ejemplo, si tiene un alias de shell:
y desea usar
bar
pero con--flag1
deshabilitado, le permite hacer:fuente
fuente
getopt()
ogetopt_long()
.Plantilla instructiva para analizar argumentos de línea de comando en C.
C:> nombre del programa -w - fileOne.txt fileTwo.txt
fuente
_Bool
en todo momento, y un encabezado<stdbool.h>
que definebool
como_Bool
ytrue
yfalse
y__bool_true_false_are_defined
, todas las macros (que, excepcionalmente, pueden estar indefinidas y redefinidas sin invocar un comportamiento indefinido; esa licencia, sin embargo, está etiquetada como 'obsoleta'). Entonces, si tiene un compilador C99, puede usar<stdbool.h>
ybool
. Si no es así, escribe uno para ti (no es difícil) o utilizas un equivalente nativo.fuente
De acuerdo, ese es el comienzo de una larga historia: abreviado 'bort analizando una línea de comando en C ...
Tenga en cuenta que esta versión también admitirá la combinación de argumentos: así que en lugar de escribir / h / s -> / hs también funcionará.
Perdón por ser la enésima persona que publica aquí; sin embargo, no estaba realmente satisfecho con todas las versiones independientes que vi aquí. Bueno, los lib son bastante agradables. Así que preferiría el analizador de opciones libUCW , Arg o Getopt sobre los caseros.
Tenga en cuenta que puede cambiar:
*++argv[i]
->(++argv*)[0]
más largo menos críptico pero aún críptico.Bien, vamos a desglosarlo: 1. argv [i] -> acceda al elemento i-ésimo en el campo de puntero argv-char
++ * ... -> reenviará el puntero argv por un carácter
... [0] -> seguirá el puntero leer el carácter
++ (...) -> corchetes están ahí, así que aumentaremos el puntero y no el valor del carácter en sí.
Tan agradable que en C ## los punteros 'murieron' - ¡¡¡Viva los punteros !!!
fuente