Ich versuche ein Programm zu schreiben, das zwei Dateien Zeile für Zeile, Wort für Wort oder Zeichen für Zeichen in C vergleichen kann. Es muss in der Lage sein, Befehlszeilenoptionen einzulesen -l -w -i or --
...
- Wenn die Option -l ist, werden die Dateien Zeile für Zeile verglichen.
- Wenn die Option -w ist, werden die Dateien Wort für Wort verglichen.
- Wenn die Optionen aktiviert sind, wird automatisch davon ausgegangen, dass das nächste Argument der erste Dateiname ist.
- Wenn die Option -i ist, werden sie ohne Berücksichtigung der Groß- und Kleinschreibung verglichen.
- Standardmäßig werden die Dateien zeichenweise verglichen.
Es spielt keine Rolle, wie oft die Optionen eingegeben werden, solange -w und -l nicht gleichzeitig eingegeben werden und nicht mehr oder weniger als 2 Dateien vorhanden sind.
Ich weiß nicht einmal, wo ich mit dem Parsen der Befehlszeilenargumente beginnen soll. BITTE HILFE :(
Das ist also der Code, den ich mir für alles ausgedacht habe. Ich habe den Fehler noch nicht überprüft, aber ich habe mich gefragt, ob ich die Dinge zu kompliziert schreibe.
/*
* 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
user1251020
quelle
quelle
Antworten:
Meines Wissens sind die drei beliebtesten Methoden zum Parsen von Befehlszeilenargumenten in C:
#include <unistd.h>
aus der POSIX C-Bibliothek), mit dem einfache Aufgaben zum Parsen von Argumenten gelöst werden können . Wenn Sie mit Bash ein wenig vertraut sind, basiert das in Bash integrierte getopt auf Getopt aus der GNU libc.#include <argp.h>
aus der GNU C Library), das komplexere Aufgaben lösen kann und sich um Dinge kümmert, wie zum Beispiel:-?
,--help
für Hilfemeldung , einschließlich E-Mail-Adresse-V
,--version
für Versionsinformationen--usage
für NutzungsnachrichtDie Dokumentation zur GNU C-Bibliothek enthält einige schöne Beispiele für Getopt und Argp.
Beispiel für die Verwendung von Getopt
Beispiel für die Verwendung von Argp
Beispiel für das Selbermachen
Haftungsausschluss: Ich bin neu in Argp, das Beispiel könnte Fehler enthalten.
quelle
Verwenden Sie
getopt()
oder vielleichtgetopt_long()
.Beachten Sie, dass Sie bestimmen müssen, welche Header enthalten sein sollen (ich mache es 4, die erforderlich sind), und die Art und Weise, wie ich den
op_mode
Typ geschrieben habe, bedeutet, dass Sie ein Problem in der Funktion habenprocess()
- Sie können dort unten nicht auf die Aufzählung zugreifen. Es ist am besten, die Aufzählung außerhalb der Funktion zu verschieben. Sie können sogarop_mode
eine Dateibereichsvariable ohne externe Verknüpfung erstellen (eine ausgefallene Art zu sagenstatic
), um zu vermeiden, dass sie an die Funktion übergeben wird. Dieser Code ist kein-
Synonym für Standardeingabe, eine weitere Übung für den Leser. Beachten Sie, dassgetopt()
automatisch--
das Ende der Optionen für Sie markiert wird.Ich habe keine Version der obigen Eingabe hinter einem Compiler ausgeführt. Es könnte Fehler geben.
Schreiben Sie für zusätzliche Gutschriften eine (Bibliotheks-) Funktion:
Dies kapselt die Logik für die Verarbeitung von Dateinamenoptionen nach der
getopt()
Schleife. Es sollte-
als Standardeingabe behandelt werden. Beachten Sie, dass die Verwendung dieser Option darauf hinweist, dass esop_mode
sich um eine statische Dateibereichsvariable handeln sollte. Diefilter()
Funktion übernimmtargc
,argv
,optind
und ein Zeiger auf die Verarbeitungsfunktion. Es sollte 0 (EXIT_SUCCESS) zurückgeben, wenn es in der Lage war, alle Dateien und alle Aufrufe der Funktion 0 zu öffnen, andernfalls 1 (oder EXIT_FAILURE). Eine solche Funktion vereinfacht das Schreiben von Unix-Filterprogrammen, die in der Befehlszeile oder in der Standardeingabe angegebene Dateien lesen.quelle
getopt()
nicht; GNUgetopt()
tut dies standardmäßig. Treffen Sie Ihre Wahl. Ich bin nicht begeistert von den Optionen nach dem Verhalten von Dateinamen, hauptsächlich weil sie plattformübergreifend nicht zuverlässig sind.Ich habe festgestellt, dass Gengetopt sehr nützlich ist - Sie geben die gewünschten Optionen mit einer einfachen Konfigurationsdatei an und es wird ein .c / .h-Paar generiert, das Sie einfach einschließen und mit Ihrer Anwendung verknüpfen. Der generierte Code verwendet getopt_long, scheint die gängigsten Arten von Befehlszeilenparametern zu verarbeiten und kann viel Zeit sparen.
Eine gengetopt-Eingabedatei könnte ungefähr so aussehen:
Das Generieren des Codes ist einfach und spuckt aus
cmdline.h
undcmdline.c
:Der generierte Code ist einfach zu integrieren:
Wenn Sie zusätzliche Überprüfungen durchführen müssen (z. B. sicherstellen, dass sich Flags gegenseitig ausschließen), können Sie dies relativ einfach mit den in der
gengetopt_args_info
Struktur gespeicherten Daten tun .quelle
#include
, nein, ich meine, die Pragmas um das zu legen , nicht in die generierte Datei selbst. Warnungen auszuschalten ist mir verboten :-)Ich bin sehr überrascht, dass niemand James Theilers "opt" -Paket angesprochen hat.
Sie finden opt unter http://public.lanl.gov/jt/Software/
und ein schmeichelhafter Beitrag mit einigen Beispielen dafür, wie viel einfacher es ist als andere Ansätze, ist hier:
http://www.decompile.com/not_invented_here/opt/
quelle
Docopt hat eine C-Implementierung, die ich sehr nett fand: https://github.com/docopt/docopt.c
Aus einem standardisierten Manpage-Format, das Befehlszeilenoptionen beschreibt, leitet docopt einen Argumentparser ab und erstellt ihn. Dies wurde in Python begonnen; Die Python-Version analysiert buchstäblich nur die Dokumentzeichenfolge und gibt ein Diktat zurück. Dies in C zu tun, erfordert etwas mehr Arbeit, ist jedoch sauber zu verwenden und weist keine externen Abhängigkeiten auf.
quelle
Es gibt eine großartige Allzweck-C-Bibliothek libUCW, die ordentliches Parsen von Befehlszeilenoptionen und Laden von Konfigurationsdateien umfasst .
Die Bibliothek enthält auch eine gute Dokumentation und einige andere nützliche Dinge (schnelle E / A, Datenstrukturen, Allokatoren, ...), die jedoch separat verwendet werden können.
Beispiel für einen libUCW-Optionsparser (aus den Bibliotheksdokumenten)
quelle
Ich habe eine winzige Bibliothek namens XOpt geschrieben, die Argumente ähnlich wie POpt analysiert, mit denen ich mehrere Probleme hatte . Verwendet das Parsen von Argumenten im GNU-Stil und hat eine sehr ähnliche Oberfläche wie POpt.
Ich benutze es von Zeit zu Zeit mit großem Erfolg und es funktioniert so ziemlich überall.
quelle
Wenn ich mein eigenes Horn betätigen darf, möchte ich auch vorschlagen, einen Blick auf eine von mir geschriebene Option zum Parsen von Bibliotheken zu werfen: dropt .
Eine Funktion, die viele andere nicht bieten, ist die Möglichkeit, frühere Optionen zu überschreiben. Wenn Sie beispielsweise einen Shell-Alias haben:
und Sie möchten verwenden,
bar
aber mit--flag1
deaktiviert, können Sie Folgendes tun:quelle
quelle
getopt()
odergetopt_long()
.Anweisungsvorlage zum Parsen von Befehlszeilenargumenten in C.
C:> programName -w - fileOne.txt fileTwo.txt
quelle
_Bool
zu jeder Zeit einen Typ und einen Header,<stdbool.h>
derbool
als_Bool
undtrue
undfalse
und__bool_true_false_are_defined
alle Makros definiert (die ausnahmsweise undefiniert und neu definiert werden können, ohne undefiniertes Verhalten aufzurufen; diese Lizenz ist jedoch als "veraltet" gekennzeichnet). Wenn Sie also einen C99-Compiler haben, können Sie<stdbool.h>
und verwendenbool
. Wenn nicht, schreiben Sie entweder eine für sich selbst (es ist nicht schwer) oder Sie verwenden ein natives Äquivalent.quelle
Okay, das ist der Beginn einer langen Geschichte - kurz gemacht, um eine Befehlszeile in C zu analysieren ...
Beachten Sie, dass diese Version auch das Kombinieren von Argumenten unterstützt: Anstatt zu schreiben, funktioniert / h / s -> / hs auch.
Es tut mir leid, dass ich die n-te Person bin, die hier schreibt - aber ich war nicht wirklich zufrieden mit all den Standalone-Versionen, die ich hier gesehen habe. Nun, die lib sind ganz nett. Daher würde ich den libUCW- Optionsparser Arg oder Getopt einem hausgemachten vorziehen .
Beachten Sie, dass Sie Folgendes ändern können:
*++argv[i]
->(++argv*)[0]
länger weniger kryptisch aber immer noch kryptisch.Okay, lassen Sie es uns zusammenfassen: 1. argv [i] -> Zugriff auf das i-te Element im argv-char-Zeigerfeld
++ * ... -> leitet den argv-Zeiger um ein Zeichen weiter
... [0] -> folgt dem Zeiger, liest das Zeichen
++ (...) -> Klammern sind vorhanden, daher erhöhen wir den Zeiger und nicht den Zeichenwert selbst.
So schön, dass in C ## die Zeiger 'gestorben' sind - es lebe die Zeiger !!!
quelle