Saya mencoba menulis sebuah program yang dapat membandingkan dua file baris demi baris, kata demi kata, atau karakter demi karakter dalam C. Program itu harus dapat membaca dalam opsi baris perintah -l -w -i or --
...
- jika opsi -l ini membandingkan file baris demi baris.
- jika opsinya adalah -w itu membandingkan file kata demi kata.
- jika opsinya adalah - secara otomatis mengasumsikan bahwa arg berikutnya adalah nama file pertama.
- jika opsinya adalah -i maka akan membandingkannya dengan cara yang tidak membedakan huruf besar / kecil.
- default untuk membandingkan karakter file dengan karakter.
Tidak masalah berapa kali opsi dimasukkan selama -w dan -l tidak dimasukkan pada saat yang sama dan tidak lebih atau kurang dari 2 file.
Saya bahkan tidak tahu harus mulai dari mana dengan mengurai argumen baris perintah. TOLONG BANTU :(
Jadi ini adalah kode yang saya buat untuk semuanya. Saya belum memeriksanya dengan kesalahan, tetapi saya bertanya-tanya apakah saya menulis sesuatu dengan cara yang terlalu rumit?
/*
* 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
pengguna1251020
sumber
sumber
Jawaban:
Sepengetahuan saya, tiga cara paling populer untuk mengurai argumen baris perintah di C adalah:
#include <unistd.h>
dari Pustaka C POSIX), yang dapat menyelesaikan tugas penguraian argumen sederhana . Jika Anda sedikit terbiasa dengan bash, getopt bawaan dari bash didasarkan pada Getopt dari GNU libc.#include <argp.h>
dari GNU C Library), yang dapat menyelesaikan tugas yang lebih kompleks dan menangani hal-hal seperti, misalnya:-?
,--help
untuk pesan bantuan , termasuk alamat email-V
,--version
untuk informasi versi--usage
untuk pesan penggunaanDokumentasi GNU C Library memiliki beberapa contoh bagus untuk Getopt dan Argp.
Contoh penggunaan Getopt
Contoh penggunaan Argp
Contoh untuk Melakukannya Sendiri
Penafian: Saya baru mengenal Argp, contohnya mungkin mengandung kesalahan.
sumber
Gunakan
getopt()
, atau mungkingetopt_long()
.Perhatikan bahwa Anda perlu menentukan header mana yang akan disertakan (saya membuatnya 4 yang diperlukan), dan cara saya menulis
op_mode
jenisnya berarti Anda memiliki masalah dalam fungsinyaprocess()
- Anda tidak dapat mengakses pencacahan di sana. Yang terbaik adalah memindahkan pencacahan di luar fungsi; Anda bahkan dapat membuatop_mode
variabel cakupan file tanpa tautan eksternal (cara yang bagus untuk mengatakannyastatic
) untuk menghindari meneruskannya ke fungsi. Kode ini tidak menangani-
sebagai sinonim untuk input standar, latihan lain untuk pembaca. Perhatikan bahwagetopt()
secara otomatis menangani--
untuk menandai akhir opsi untuk Anda.Saya belum menjalankan versi apa pun dari pengetikan di atas melewati kompiler; mungkin ada kesalahan di dalamnya.
Untuk kredit ekstra, tulis fungsi (perpustakaan):
yang merangkum logika untuk memproses opsi nama file setelah
getopt()
pengulangan. Ini harus ditangani-
sebagai input standar. Perhatikan bahwa menggunakan ini akan menunjukkan bahwaop_mode
seharusnya variabel cakupan file statis. Thefilter()
fungsi mengambilargc
,argv
,optind
dan pointer ke fungsi pengolahan. Ini harus mengembalikan 0 (EXIT_SUCCESS) jika ia dapat membuka semua file dan semua pemanggilan fungsi yang dilaporkan 0, jika tidak 1 (atau EXIT_FAILURE). Memiliki fungsi seperti itu menyederhanakan penulisan program 'filter' gaya Unix yang membaca file yang ditentukan pada baris perintah atau input standar.sumber
getopt()
tidak; GNUgetopt()
melakukannya secara default. Ambil pilihanmu. Saya tidak tertarik pada opsi setelah perilaku nama file, terutama karena tidak dapat diandalkan di seluruh platform.Saya telah menemukan Gengetopt cukup berguna - Anda menentukan opsi yang Anda inginkan dengan file konfigurasi sederhana, dan itu menghasilkan pasangan .c / .h yang cukup Anda sertakan dan tautkan dengan aplikasi Anda. Kode yang dihasilkan menggunakan getopt_long, tampaknya menangani jenis parameter baris perintah yang paling umum, dan dapat menghemat banyak waktu.
File masukan gengetopt mungkin terlihat seperti ini:
Membuat kode itu mudah dan mudah
cmdline.h
dancmdline.c
:Kode yang dihasilkan mudah diintegrasikan:
Jika Anda perlu melakukan pemeriksaan tambahan (seperti memastikan flag saling eksklusif), Anda dapat melakukannya dengan cukup mudah dengan data yang disimpan di
gengetopt_args_info
struct.sumber
#include
, bukan di file yang dihasilkan itu sendiri. bagi saya mematikan peringatan adalah verboten :-)Saya sangat terkejut tidak ada yang menyinggung paket "opt" James Theiler.
Anda dapat menemukan opt di http://public.lanl.gov/jt/Software/
dan posting yang bagus dengan beberapa contoh bagaimana itu jauh lebih sederhana daripada pendekatan lain di sini:
http://www.decompile.com/not_invented_here/opt/
sumber
Docopt memiliki implementasi C yang menurut saya cukup bagus: https://github.com/docopt/docopt.c
Dari format standar halaman manual yang menjelaskan opsi baris perintah, docopt menyimpulkan dan membuat parser argumen. Ini dimulai dengan python; versi python secara harfiah hanya mem-parsing docstring dan mengembalikan sebuah dict. Untuk melakukan ini di C membutuhkan sedikit lebih banyak pekerjaan, tetapi bersih untuk digunakan dan tidak memiliki ketergantungan eksternal.
sumber
Ada pustaka C libUCW serbaguna yang mencakup penguraian opsi baris perintah yang rapi dan pemuatan file konfigurasi .
Pustaka juga dilengkapi dengan dokumentasi yang baik dan menyertakan beberapa hal berguna lainnya (IO cepat, struktur data, pengalokasi, ...) tetapi ini dapat digunakan secara terpisah.
Contoh parser opsi libUCW (dari dokumen perpustakaan)
sumber
Saya menulis perpustakaan kecil yang mem-parsing argumen yang mirip dengan POpt, yang memiliki beberapa masalah dengan saya, yang disebut XOpt . Menggunakan penguraian argumen gaya GNU dan memiliki antarmuka yang sangat mirip dengan POpt.
Saya menggunakannya dari waktu ke waktu dengan sukses besar, dan berhasil hampir di mana saja.
sumber
Sambil mengomel sendiri jika boleh, saya juga ingin menyarankan untuk melihat opsi parsing library yang telah saya tulis: dropt .
Salah satu fitur yang ditawarkannya yang tidak ditawarkan oleh banyak orang lain adalah kemampuan untuk mengganti opsi sebelumnya. Misalnya, jika Anda memiliki alias shell:
dan Anda ingin menggunakan
bar
tetapi dengan--flag1
nonaktif, ini memungkinkan Anda untuk melakukan:sumber
sumber
getopt()
ataugetopt_long()
.Template instruksional untuk mengurai argumen baris perintah di C.
C:> programName -w - fileOne.txt fileTwo.txt
sumber
_Bool
setiap saat, dan header<stdbool.h>
yang mendefinisikanbool
sebagai_Bool
dantrue
danfalse
dan__bool_true_false_are_defined
, semua macro (yang, sangat, dapat terdefinisi dan didefinisikan ulang tanpa melibatkan perilaku undefined, lisensi yang, bagaimanapun, tagged 'usang'). Jadi, jika Anda memiliki kompiler C99, Anda dapat menggunakan<stdbool.h>
danbool
. Jika tidak, Anda dapat menuliskannya untuk diri Anda sendiri (tidak sulit) atau Anda menggunakan padanan asli.sumber
Oke itulah awal dari cerita panjang - dibuat pendek 'bort parsing baris perintah di C ...
Perhatikan bahwa versi ini juga akan mendukung penggabungan argumen: Jadi daripada menulis / h / s -> / hs juga akan berfungsi.
Maaf karena menjadi orang ke-n yang memposting di sini - namun saya tidak terlalu puas dengan semua versi mandiri yang saya lihat di sini. Yang lib cukup bagus. Jadi saya lebih suka parser opsi libUCW , Arg atau Getopt daripada yang dibuat sendiri.
Perhatikan bahwa Anda dapat mengubah:
*++argv[i]
->(++argv*)[0]
lagi lebih sedikit samar tapi masih samar.Oke mari kita hancurkan: 1. argv [i] -> akses elemen ke-i di bidang pointer argv-char
++ * ... -> akan meneruskan argv-pointer dengan satu karakter
... [0] -> akan mengikuti pointer membaca karakter
++ (...) -> braket ada sehingga kami akan meningkatkan penunjuk dan bukan nilai karakter itu sendiri.
Begitu bagusnya di C ## petunjuknya 'mati' - panjang umur petunjuknya !!!
sumber