Я пытаюсь написать программу, которая может сравнивать два файла строка за строкой, слово за словом или символ за символом в C.Она должна иметь возможность читать в параметрах командной строки -l -w -i or --
...
- если опция -l, он сравнивает файлы построчно.
- если параметр -w, он сравнивает файлы слово за словом.
- если опция - это автоматически предполагает, что следующий аргумент является первым именем файла.
- если опция -i, он сравнивает их без учета регистра.
- по умолчанию выполняется посимвольное сравнение файлов.
Не имеет значения, сколько раз вводятся параметры, если -w и -l не вводятся одновременно и файлов не больше или не меньше.
Я даже не знаю, с чего начать анализ аргументов командной строки. ПОЖАЛУЙСТА ПОМОГИ :(
Вот код, который я придумал для всего. Я еще не проверил ошибку, но мне было интересно, не пишу ли я слишком сложно?
/*
* 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
источник
источник
Ответы:
Насколько мне известно, три наиболее популярных способа анализа аргументов командной строки в C:
#include <unistd.h>
из библиотеки POSIX C), которая может решить простой синтаксический анализ аргументов задачи . Если вы немного знакомы с bash, встроенный в bash getopt основан на Getopt из GNU libc.#include <argp.h>
из библиотеки GNU C), который может решать более сложные задачи и заботится о таких вещах, как, например:-?
,--help
для справочного сообщения , включая адрес электронной почты-V
,--version
для информации о версии--usage
для сообщения об использованииВ документации библиотеки GNU C есть несколько хороших примеров для Getopt и Argp.
Пример использования Getopt
Пример использования Argp
Пример самостоятельного выполнения
Отказ от ответственности: я новичок в Argp, пример может содержать ошибки.
источник
Использовать
getopt()
, а может бытьgetopt_long()
.Обратите внимание, что вам нужно определить, какие заголовки включать (я делаю их 4 обязательными), и то, как я написал
op_mode
тип, означает, что у вас есть проблема в функцииprocess()
- вы не можете получить доступ к перечислению там. Лучше всего вынести перечисление за пределы функции; вы можете даже создатьop_mode
переменную области файла без внешней связи (причудливый способ сказатьstatic
), чтобы не передавать ее функции. Этот код не рассматривается-
как синоним стандартного ввода, еще одно упражнение для читателя. Обратите внимание, чтоgetopt()
автоматически--
отметит конец опций для вас.Я не запускал ни одной версии вышеописанной типизации без компилятора; в нем могли быть ошибки.
Для дополнительного кредита напишите (библиотечную) функцию:
который инкапсулирует логику обработки параметров имени файла после
getopt()
цикла. Он должен обрабатываться-
как стандартный ввод. Обратите внимание, что использование этого параметра будет означать, что этоop_mode
должна быть статическая переменная области видимости файла.filter()
Функция принимаетargc
,argv
,optind
и указатель на функцию обработки. Он должен вернуть 0 (EXIT_SUCCESS), если ему удалось открыть все файлы и все вызовы функции, о которых сообщалось 0, в противном случае 1 (или EXIT_FAILURE). Наличие такой функции упрощает написание программ «фильтров» в стиле Unix, которые читают файлы, указанные в командной строке или стандартном вводе.источник
getopt()
этого не делает; GNUgetopt()
делает это по умолчанию. Сделайте ваш выбор. Мне не нравятся варианты поведения после имен файлов, в основном потому, что они ненадежны для разных платформ.Я обнаружил, что Gengetopt весьма полезен - вы указываете нужные параметры с помощью простого файла конфигурации, и он генерирует пару .c / .h, которую вы просто включаете и связываете с вашим приложением. Сгенерированный код использует getopt_long, по-видимому, обрабатывает наиболее распространенные типы параметров командной строки и может сэкономить много времени.
Входной файл gengetopt может выглядеть примерно так:
Генерация кода легко и выплевывает
cmdline.h
иcmdline.c
:Сгенерированный код легко интегрируется:
Если вам нужно выполнить дополнительную проверку (например, убедиться, что флаги являются взаимоисключающими), вы можете сделать это довольно легко с данными, хранящимися в
gengetopt_args_info
структуре.источник
#include
, а не в самом сгенерированном файле. для меня отключение предупреждений запрещено :-)Я очень удивлен, что никто не поднял "opt" пакет Джеймса Тайлера.
Вы можете найти опцию на http://public.lanl.gov/jt/Software/
и лестный пост с примерами того, как это намного проще, чем другие подходы, здесь:
http://www.decompile.com/not_invented_here/opt/
источник
В Docopt есть реализация на языке C, которая мне показалась довольно хорошей: https://github.com/docopt/docopt.c
Из стандартизованного формата страницы руководства, описывающего параметры командной строки, docopt выводит и создает синтаксический анализатор аргументов. Это началось в python; версия на Python буквально просто анализирует строку документации и возвращает dict. Чтобы сделать это на C, потребуется немного больше работы, но он прост в использовании и не имеет внешних зависимостей.
источник
Существует отличная библиотека C общего назначения libUCW, которая включает аккуратный синтаксический анализ параметров командной строки и загрузку файла конфигурации .
Библиотека также поставляется с хорошей документацией и включает некоторые другие полезные вещи (быстрый ввод-вывод, структуры данных, распределители ...), но это можно использовать отдельно.
Пример парсера опций libUCW (из документации библиотеки)
источник
Я написал крошечную библиотеку, которая анализирует аргументы, аналогичные POpt, с которой у меня было несколько проблем, под названием XOpt . Использует синтаксический анализ аргументов в стиле GNU и имеет интерфейс, очень похожий на POpt.
Я использую его время от времени с большим успехом, и он работает практически везде.
источник
Поручая свой собственный рог, если можно, я также хотел бы предложить взглянуть на библиотеку синтаксического анализа параметров, которую я написал: dropt .
Одна функция, которую он предлагает, которой нет у многих других, - это возможность переопределить предыдущие параметры. Например, если у вас есть псевдоним оболочки:
и вы хотите использовать,
bar
но с--flag1
отключенным, он позволяет вам:источник
источник
getopt()
илиgetopt_long()
.Обучающий шаблон для синтаксического анализа аргументов командной строки в C.
C:> имя_программы -w - fileOne.txt fileTwo.txt
источник
_Bool
и заголовок,<stdbool.h>
который определяетbool
как_Bool
andtrue
иfalse
and__bool_true_false_are_defined
, все макросы (которые, в исключительных случаях, могут быть неопределенными и переопределенными без вызова неопределенного поведения; эта лицензия, однако, помечена как «устаревшая»). Итак, если у вас есть компилятор C99, вы можете использовать<stdbool.h>
иbool
. Если нет, вы либо напишите его для себя (это несложно), либо воспользуетесь собственным эквивалентом.источник
Ладно, это начало длинной истории - краткий анализ командной строки на C ...
Обратите внимание, что эта версия также поддерживает объединение аргументов: Итак, вместо записи / h / s -> / hs также будет работать.
Извините за то, что я n-ый человек, разместивший здесь - однако я не был полностью удовлетворен всеми автономными версиями, которые я видел здесь. Что ж, библиотеки lib перестали быть хорошими. Поэтому я бы предпочел парсер опций libUCW , Arg или Getopt самодельным.
Обратите внимание, что вы можете изменить:
*++argv[i]
->(++argv*)[0]
дольше менее загадочно, но все же загадочно.Хорошо, давайте разберемся: 1. argv [i] -> доступ к i-му элементу в поле указателя argv-char
++ * ... -> перенаправит указатель argv на один символ
... [0] -> будет следовать за указателем, читать символ
++ (...) -> скобка, поэтому мы увеличим указатель, а не само значение char.
Так приятно, что в C ## указатели «умерли» - да здравствуют указатели !!!
источник