C'de komut satırı bağımsız değişkenleri ayrıştırılıyor mu?


103

C de iki dosyayı satır satır, kelime kelime veya karakter karakter karşılaştırabilen bir program yazmaya çalışıyorum.Komut satırı seçeneklerini okuyabilmeli -l -w -i or --...

  • seçeneği -l ise, dosyaları satır satır karşılaştırır.
  • seçeneği -w ise dosyaları kelime kelime karşılaştırır.
  • seçenekler ise - otomatik olarak sonraki bağımsız değişkenin ilk dosya adı olduğunu varsayar.
  • seçeneği -i ise, bunları büyük / küçük harfe duyarlı olmayan bir şekilde karşılaştırır.
  • varsayılan olarak dosyaları karakter karakter karşılaştırmaktır.

-W ve -l aynı anda girilmediği ve 2'den fazla veya az dosya olmadığı sürece, seçeneklerin kaç kez girildiği önemli değildir.

Komut satırı argümanlarını çözümlemeye nereden başlayacağımı bile bilmiyorum. LÜTFEN YARDIM ET :(

İşte her şey için bulduğum kod bu. Henüz hatayı kontrol etmedim, ancak bir şeyleri aşırı karmaşık bir şekilde yazıp yazmadığımı merak ediyordum.

/*
 * 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;
}

Getopt () 'u nasıl kullanacağımdan tam olarak emin değilim ... Henüz sınıfımda öğrenmedim.
user1251020

3
Öyleyse gidin ve bunun için kılavuz sayfasını okuyun; çok karmaşık değildir ve kılavuz sayfası muhtemelen denemeniz için bir örnek içerir (ve yerel kılavuz sayfanız yoksa, web'de kesinlikle örnekler bulabilirsiniz).
Jonathan Leffler

1
Bu yüksek seviyeli bir kütüphanedir: c'de argparse , kullanımı çok kolay.
Cofyc


Basit şeyler için bir kitaplık kullanmak yerine kendinizinkini yuvarlayabilirsiniz. Burada Engineeringterminal.com/computer-science/tutorials/…
nalyd88

Yanıtlar:


192

Bildiğim kadarıyla, C'deki komut satırı argümanlarını çözümlemenin en popüler üç yolu:

  • Getopt ( #include <unistd.h>POSIX C Kitaplığından), basit argüman ayrıştırma görevlerini çözebilir . Eğer bash'a biraz aşinaysanız, bash'ın getopt yerleşik bileşeni GNU libc'den Getopt'a dayanır.
  • Argp ( #include <argp.h>GNU C Kütüphanesinden), daha karmaşık görevleri çözebilen ve örneğin:
    • -?, --helpİçin yardım mesajının dahil e-posta adresi
    • -V, --versionİçin sürüm bilgisi
    • --usageiçin kullanım mesajının
  • Kendiniz yapmak, ki bunu başkasına verilecek programlar için önermiyorum, çünkü yanlış gidebilecek veya daha düşük kalitede olabilecek çok şey var. Seçenek ayrıştırmayı durdurmak için '-' unutmanın popüler hatası sadece bir örnektir.

GNU C Kitaplığı belgelerinde Getopt ve Argp için bazı güzel örnekler vardır.

Getopt kullanma örneği

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    bool isCaseInsensitive = false;
    int opt;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;

    while ((opt = getopt(argc, argv, "ilw")) != -1) {
        switch (opt) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument.
    // If it is >= argc, there were no non-option arguments.

    // ...
}

Argp kullanma örneği

#include <argp.h>
#include <stdbool.h>

const char *argp_program_version = "programname programversion";
const char *argp_program_bug_address = "<your@email.address>";
static char doc[] = "Your program description.";
static char args_doc[] = "[FILENAME]...";
static struct argp_option options[] = { 
    { "line", 'l', 0, 0, "Compare lines instead of characters."},
    { "word", 'w', 0, 0, "Compare words instead of characters."},
    { "nocase", 'i', 0, 0, "Compare case insensitive instead of case sensitive."},
    { 0 } 
};

struct arguments {
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode;
    bool isCaseInsensitive;
};

static error_t parse_opt(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;
    switch (key) {
    case 'l': arguments->mode = LINE_MODE; break;
    case 'w': arguments->mode = WORD_MODE; break;
    case 'i': arguments->isCaseInsensitive = true; break;
    case ARGP_KEY_ARG: return 0;
    default: return ARGP_ERR_UNKNOWN;
    }   
    return 0;
}

static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 };

int main(int argc, char *argv[])
{
    struct arguments arguments;

    arguments.mode = CHARACTER_MODE;
    arguments.isCaseInsensitive = false;

    argp_parse(&argp, argc, argv, 0, 0, &arguments);

    // ...
}

Kendin Yapma Örneği

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
    bool isCaseInsensitive = false;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
    size_t optind;
    for (optind = 1; optind < argc && argv[optind][0] == '-'; optind++) {
        switch (argv[optind][1]) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }   
    }   

    // *argv points to the remaining non-option arguments.
    // If *argv is NULL, there were no non-option arguments.

    // ...
}   

Sorumluluk reddi: Argp'ta yeniyim, örnek hatalar içerebilir.


9
Gerçekten kapsamlı cevap, teşekkürler Christian (olumlu oy verildi). Ancak, mac kullanıcıları argp yaklaşımının platformlar arası uyumlu olmadığının farkında olmalıdır. Bulduğum gibi burada , Argp olmayan bir standardize glibc API uzantısıdır. Gnulib'de mevcuttur, bu nedenle bir projeye açıkça eklenebilir. Ancak, yalnızca Mac veya çapraz platform geliştiricilerinin getopt yaklaşımını kullanması muhtemelen daha kolaydır.
thclark

1
Kendin yap sürümü için, seçeneklerin daha sonra fazladan metne izin vermesini, -wzzz'nin -w ile aynı şekilde ayrıştırması ve ayrıca seçeneklerin dosya bağımsız değişkenlerinden önce gelmesi gerektiğini sevmiyorum.
Jake

1
@Jake haklısın. Bunu fark etmeye saygı duyun. Bunu yazarken fark edip görmediğimi hatırlamıyorum. Yine, DIY'in yanılmasının çok kolay olduğu ve bu yüzden yapılmaması gereken mükemmel bir örnek. Anlattığın için teşekkürler, örneği düzeltebilirim.
Christian Hujer

18

Kullan getopt()ya da belki getopt_long().

int iflag = 0;
enum { WORD_MODE, LINE_MODE } op_mode = WORD_MODE;  // Default set
int opt;

while ((opt = getopt(argc, argv, "ilw") != -1)
{
    switch (opt)
    {
    case 'i':
        iflag = 1;
        break;
    case 'l':
        op_mode = LINE_MODE;
        break;
    case 'w':
        op_mode = WORD_MODE;
        break;
    default:
        fprintf(stderr, "Usage: %s [-ilw] [file ...]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
}

/* Process file names or stdin */
if (optind >= argc)
    process(stdin, "(standard input)", op_mode);
else
{
    int i;
    for (i = optind; i < argc; i++)
    {
        FILE *fp = fopen(argv[i], "r");
        if (fp == 0)
            fprintf(stderr, "%s: failed to open %s (%d %s)\n",
                    argv[0], argv[i], errno, strerror(errno));
        else
        {
            process(fp, argv[i], op_mode);
            fclose(fp);
        }
    }
 }

Hangi başlıkları dahil edeceğinizi belirlemeniz gerektiğini unutmayın (gerekli olanları 4 yapıyorum) ve op_modetürü process()yazma şeklim , işlevde bir sorununuz olduğu anlamına gelir - oradaki numaralandırmaya erişemezsiniz. Numaralamayı işlevin dışına taşımak en iyisidir; Hatta işleve geçmekten kaçınmak için op_modeharici bağlantı olmadan bir dosya kapsamı değişkeni bile oluşturabilirsiniz (söylemenin süslü bir yolu static). Bu kod -, okuyucu için başka bir alıştırma olan standart girişle eşanlamlı olarak ele alınmaz . Not getopt()otomatik ilgilenir --sizin için seçeneklerin sonunu işaretlemek için.

Bir derleyicinin üzerine yazmanın herhangi bir sürümünü çalıştırmadım; içinde hatalar olabilir.


Ekstra kredi için bir (kitaplık) işlevi yazın:

int filter(int argc, char **argv, int idx, int (*function)(FILE *fp, const char *fn));

getopt()döngüden sonra dosya adı seçeneklerini işleme mantığını içerir . Bu işlemesi gerektiğini -standart girdi olarak. Bunu kullanmanın op_modestatik bir dosya kapsamı değişkeni olması gerektiğini göstereceğini unutmayın . filter()İşlev alır argc, argv, optindve işleme işlevi için işaretçi. 0 (veya EXIT_FAILURE) olarak rapor edilen fonksiyonun tüm dosyalarını ve tüm çağrılarını açabildiyse 0 (EXIT_SUCCESS) döndürmelidir. Böyle bir işleve sahip olmak, komut satırında veya standart girişte belirtilen dosyaları okuyan Unix tarzı 'filtre' programları yazmayı kolaylaştırır.


Getopt () 'un ilk dosyadan sonra seçeneklere izin vermemesi hoşuma gitmiyor.
Jake

POSIX getopt()yapmaz; GNU getopt()varsayılan olarak yapar. İstediğini al. Dosya adı davranışından sonraki seçeneklere meraklı değilim, çünkü temelde platformlar arasında güvenilir değil.
Jonathan Leffler

14

Gengetopt'u oldukça kullanışlı buldum - istediğiniz seçenekleri basit bir yapılandırma dosyasıyla belirtirsiniz ve basitçe dahil edip uygulamanıza bağladığınız bir .c / .h çifti oluşturur. Oluşturulan kod getopt_long'u kullanır, en yaygın komut satırı parametrelerini işliyor gibi görünür ve çok zaman kazandırabilir.

Bir gengetopt girdi dosyası şunun gibi görünebilir:

version "0.1"
package "myApp"
purpose "Does something useful."

# Options
option "filename" f "Input filename" string required
option "verbose" v "Increase program verbosity" flag off
option "id" i "Data ID" int required
option "value" r "Data value" multiple(1-) int optional 

Kodun oluşturulması kolaydır ve dışarı çıkar cmdline.hve cmdline.c:

$ gengetopt --input=myApp.cmdline --include-getopt

Oluşturulan kod kolayca entegre edilir:

#include <stdio.h>
#include "cmdline.h"

int main(int argc, char ** argv) {
  struct gengetopt_args_info ai;
  if (cmdline_parser(argc, argv, &ai) != 0) {
    exit(1);
  }
  printf("ai.filename_arg: %s\n", ai.filename_arg);
  printf("ai.verbose_flag: %d\n", ai.verbose_flag);
  printf("ai.id_arg: %d\n", ai.id_arg);
  int i;
  for (i = 0; i < ai.value_given; ++i) {
    printf("ai.value_arg[%d]: %d\n", i, ai.value_arg[i]);
  }
}

Herhangi bir ekstra kontrol yapmanız gerekirse (bayrakların karşılıklı olarak dışlanmasını sağlamak gibi), bunu gengetopt_args_infoyapı içinde depolanan verilerle oldukça kolay bir şekilde yapabilirsiniz .


1 ++, uyarı üreten kod üretmesi dışında :(
cat

Evet maalesef. Cmake dosyama istisnalar koydum.
Davida

Muhtemelen bu dosya için uyarıları görmezden gelmek için GCC pragmalarını kullanacağım (çok kötü biliyorum)
kedi

Kaynağı yeniden oluşturduğunuzda onları açıkça kaybedeceğinizi unutmayın, bu nedenle bunları derleme sürecinizde bir yama olarak uygulamak isteyebilirsiniz. Açıkçası, bu belirli dosyalardaki uyarıları kapatmayı daha kolay buldum.
Davida

iyi hayır, pragmaları #includeoluşturulan dosyanın içine değil, etrafına koymak demek istiyorum . bana uyarıları kapatmak verboten :-)
kedi

6

James Theiler'ın "opt" paketini kimsenin açmasına çok şaşırdım.

Seçimi http://public.lanl.gov/jt/Software/ adresinde bulabilirsiniz.

ve diğer yaklaşımlardan nasıl bu kadar basit olduğuna dair bazı örneklerle gurur verici bir gönderi burada:

http://www.decompile.com/not_invented_here/opt/


2
@cat O zamandan beri güncellenmesi gerektiğini düşündüren nedir? Yazılım konusunda sahip olunması gereken yanlış tutum budur.
Joshua Hedges

@JoshuaHedges Projeyi kendim sürdürmek istemediğim sürece, aktif olarak tutulan kodumda aktif olarak tutulan kodu kullanmak istiyorum. Orada aktif olarak korunur 2006 projelerin sürü var, ama bu muhtemelen Ayrıca, 2 yıl önce hata ile öldü ve (neredeyse tam!) Ben mi yazdım bu çok uzun zaman önceydi. P
kedi

1
opt, tam ve kompakt olduğundan aktif olarak korunmaz. Vuruşlar için onu indirdim ve oluşturmaya çalıştım (gcc-7.3) ve kitaplığın oluşturulduğunu ve çalıştığını gördüm, ancak C ++ testi bazı küçük çalışmalarla yapabilirdi. iostream.h, iostream haline gelmeli ve ad alanı std kullanmalıdır; eklenmiş olmalı. James'e bundan bahsedeceğim. Bu yalnızca C ++ API testini etkiler, kodun kendisini etkilemez.
markgalassi

5

Docopt'un oldukça güzel olduğunu düşündüğüm bir C uygulaması var: https://github.com/docopt/docopt.c

Docopt komut satırı seçeneklerini açıklayan standartlaştırılmış bir standart formattan çıkarır ve bir argüman ayrıştırıcısı oluşturur. Bu python ile başladı; python sürümü tam anlamıyla sadece docstring'i ayrıştırır ve bir dict döndürür. Bunu C'de yapmak biraz daha fazla çaba gerektirir, ancak kullanımı temizdir ve harici bağımlılıkları yoktur.


3

Düzgün komut satırı seçeneği ayrıştırma ve yapılandırma dosyası yüklemesi içeren harika bir genel amaçlı C kitaplığı libUCW vardır .

Kütüphane aynı zamanda iyi bir dokümantasyonla birlikte gelir ve başka yararlı şeyler içerir (hızlı GÇ, veri yapıları, ayırıcılar, ...) ancak bu ayrı olarak kullanılabilir.

Örnek libUCW seçenek ayrıştırıcısı (kitaplık belgelerinden)

#include <ucw/lib.h>
#include <ucw/opt.h>

int english;
int sugar;
int verbose;
char *tea_name;

static struct opt_section options = {
  OPT_ITEMS {
    OPT_HELP("A simple tea boiling console."),
    OPT_HELP("Usage: teapot [options] name-of-the-tea"),
    OPT_HELP(""),
    OPT_HELP("Options:"),
    OPT_HELP_OPTION,
    OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
    OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
    OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
    OPT_STRING(OPT_POSITIONAL(1), NULL, tea_name, OPT_REQUIRED, ""),
    OPT_END
  }
};

int main(int argc, char **argv)
{
  opt_parse(&options, argv+1);
  return 0;
}

konumsal seçenek hata içeriyor. iki OPT_STRING varsa ve biri konumsal ise, biri yoksa, ayrıştırılamaz.
NewBee

2

XOpt adında birkaç sorun yaşadığım, POpt'a benzer argümanları ayrıştıran küçük bir kitaplık yazdım . GNU tarzı bağımsız değişken çözümlemeyi kullanır ve POpt'a çok benzer bir arayüze sahiptir.

Zaman zaman büyük bir başarıyla kullanıyorum ve hemen hemen her yerde işe yarıyor.


1

Mümkünse kendi boynuzumu çevirerek , yazdığım bir kitaplık ayrıştırma seçeneğine de bir göz atmanızı öneririm : dropt .

  • Bu bir C kitaplığıdır (istenirse bir C ++ sarıcı ile).
  • Hafiftir.
  • Genişletilebilir (özel bağımsız değişken türleri kolayca eklenebilir ve yerleşik bağımsız değişken türleri ile eşit temele sahip olabilir).
  • Bağımlılıkları olmayan (C standart kitaplığı dışında) çok taşınabilir (standart C'de yazılmıştır) olmalıdır.
  • Çok kısıtlayıcı bir lisansa sahiptir (zlib / libpng).

Diğerlerinin sunmadığı bir özellik, önceki seçenekleri geçersiz kılma yeteneğidir. Örneğin, bir kabuk takma adınız varsa:

alias bar="foo --flag1 --flag2 --flag3"

ve kullanmak istiyorsanız, barancak --flag1devre dışı bırakıldığında şunları yapmanıza izin verir:

bar --flag1=0

0
#include <stdio.h>

int main(int argc, char **argv)
{
    size_t i;
    size_t filename_i = -1;

    for (i = 0; i < argc; i++)
    {
        char const *option =  argv[i];
        if (option[0] == '-')
        {
            printf("I am a flagged option");
            switch (option[1])
            {
                case 'a':
                    /*someting*/
                    break;
                case 'b':
                    break;
                case '-':
                    /* "--" -- the next argument will be a file.*/
                    filename_i = i;
                    i = i + 1;
                    break;
                default:
                    printf("flag not recognised %s", option);
                    break;
            }
        }
        else
        {   
            printf("I am a positional argument");
        }

        /* At this point, if -- was specified, then filename_i contains the index
         into argv that contains the filename. If -- was not specified, then filename_i will be -1*/
     }
  return 0;
}

4
Hayır; kesinlikle bunu yapmanın iyi bir yolu değil ... Bağımsız değişken çözümleme işlevlerinden birini kullanın - getopt()veya getopt_long().
Jonathan Leffler

5
Bunun apaçık bir ev ödevi sorusu olduğu düşünüldüğünde, kulağa hile gibi geliyor. Ek olarak, OP, bir dizenin ne olduğu ve bazı kısımlarının nasıl okunacağı kavramını anlamakta güçlük çekiyor. Ona jetopt atmak bir hata.
Pod

Bu bir ev ödevi sorusudur. İpin ne olduğunu biliyorum. Komut satırı argümanlarını nasıl parçalayacağımı anlamıyorum çünkü seçenekleri istediğiniz sayıda girdiğinizde kafa karıştırıcı geliyor, bu yüzden dosya adlarının nerede olduğunu gerçekten anlayamazsınız. Belki fazla düşünüyorum?
user1251020

0

C'de komut satırı bağımsız değişkenlerini ayrıştırmak için öğretim şablonu.

C:> programName -w - fileOne.txt dosyasıTwo.txt

BOOL argLine = FALSE;
BOOL argWord = FALSE;
BOOL argChar = FALSE;
char * fileName1 = NULL;
char * fileName2 = NULL;

int main(int argc, char * argv[]) {
    int i;
    printf("Argument count=%d\n",argc);
    for (i = 0; i < argc; i++) {
        printf("Argument %s\n",argv[i]);
        if (strcmp(argv[i],"-l")==0) {
            argLine = TRUE;
            printf("    argLine=TRUE\n");
        }
        else if (strcmp(argv[i],"-w")==0) {
            argWord = TRUE;
            printf("    argWord=TRUE\n");
        }
        else if (strcmp(argv[i],"-c")==0) {
            argChar = TRUE;
            printf("    argChar=TRUE\n");
        }
        else if (strcmp(argv[i],"--")==0) {
            if (i+1 <= argc) {
                fileName1 = argv[++i];
                printf("    fileName1=%s\n",fileName1);
            }
            if (i+1 <= argc) {
                fileName2 = argv[++i];
                printf("    fileName2=%s\n",fileName2);
            }
        }
    }
    return 0;
}

1
... C de boole değişkeni olduğunu sanmıyorum ...?
user1251020

Eclipse / windows ortamım BOOL tipine sahip. Basitçe int veya char yazmak için değiştirin ve kodu buna göre ayarlayın.
Java42

1
C99 tipine sahip olan _Boolher zaman ve bir başlık <stdbool.h>olan tanımlar boololarak _Boolve trueve falseve __bool_true_false_are_definedbütün makroları (derece, tanımsız ve tanımsız davranış yürütmesini olmadan yeniden edilebilir, yani lisans, ancak, isim levhası 'eskimiş'). Yani, bir C99 derleyiciniz varsa, <stdbool.h>ve kullanabilirsiniz bool. Değilse, ya kendiniz için bir tane yazarsınız (zor değildir) ya da yerel bir eşdeğerini kullanırsınız.
Jonathan Leffler

1
@Wolfer My C ortamının BOOL (typedef int BOOL olarak) ve boolean (typedef unsigned char boolean olarak) türü vardır ve bool türü için tanım yoktur. Örnekte, int veya char yazın ve kodu buna göre ayarlayın.
Java42

3
Bu yaklaşıma katılmıyorum. Seçenekleri ayrıştırmak için bir kitaplık işlevi kullanın.
Jonathan Leffler

0
    /*
      Here's a rough one not relying on any libraries.
      Example:
      -wi | -iw //word case insensitive
      -li | -il //line case insensitive
      -- file  //specify the first filename (you could just get the files
      as positional arguments in the else statement instead)
      PS: don't mind the #define's, they're just pasting code :D
    */
    #ifndef OPT_H
    #define OPT_H

    //specify option requires argument
    #define require \
      optarg = opt_pointer + 1; \
      if (*optarg == '\0') \
      { \
        if (++optind == argc) \
          goto opt_err_arg; \
        else \
          optarg = argv[optind]; \
      } \
      opt_pointer = opt_null_terminator;

    //start processing argv
    #define opt \
    int   optind                 = 1; \
    char *opt_pointer            = argv[1]; \
    char *optarg                 = NULL; \
    char  opt_null_terminator[2] = {'\0','\0'}; \
    if (0) \
    { \
      opt_err_arg: \
        fprintf(stderr,"option %c requires argument.\n",*opt_pointer); \
        return 1; \
      opt_err_opt: \
        fprintf(stderr,"option %c is invalid.\n",*opt_pointer); \
        return 1; \
    } \
    for (; optind < argc; opt_pointer = argv[++optind]) \
      if (*opt_pointer++ == '-') \
      { \
        for (;;++opt_pointer) \
          switch (*opt_pointer) \
          {

    //stop processing argv
    #define done \
          default: \
            if (*opt_pointer != '\0') \
              goto opt_err_opt; \
            else \
              goto opt_next; \
            break; \
          } \
        opt_next:; \
      }
    #endif //opt.h

    #include <stdio.h>
    #include "opt.h"
    int
    main (int argc, char **argv)
    {
      #define by_character 0
      #define by_word      1
      #define by_line      2
      int cmp = by_character;
      int case_insensitive = 0;
      opt
      case 'h':
        puts ("HELP!");
        break;
      case 'v':
        puts ("fileCMP Version 1.0");
        break;
      case 'i':
        case_insensitive = 1;
        break;
      case 'w':
        cmp = by_word;
        break;
      case 'l':
        cmp = by_line;
        break;
      case '-':required
        printf("first filename: %s\n", optarg);
        break;
      done
      else printf ("Positional Argument %s\n", argv[optind]);
      return 0;
    }

2
Kodunuzu bir kenara atmak ve herkesin anlamasını beklemek yerine açıklamanız gerekir. Bu sadece kopyalayıp yapıştırmak için değil öğrenmek için bir site.
Yokai

0

Tamam, bu uzun hikayenin başlangıcı - C'de bir komut satırı ayrıştıran kısa 'bort yapıldı ...

/**
* Helper function to parse the command line
* @param argc Argument Counter
* @param argv Argument Vector
* @param prog Program Instance Reference to fill with options
*/
bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) {
  bool pathAdded = false;

  // iterate over all arguments...
  for ( int i = 1; i<argc; i++ ) {

    // is argv a command line option ?
    if ( argv[i][0] == '-' || argv[i][0] == '/' ) {

// ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~
      // check for longer options
            if ( stricmp( &argv[i][1], "NoFileName"  ) == 0
              ||  strcmp( &argv[i][1], "q1"          ) == 0 ) {

        boNoFileNameLog = true;
      } else if ( strcmp( &argv[i][1], "HowAreYou?"    ) == 0 ) {
          logInfo( "SECRET FOUND: Well - wow I'm glad ya ask me.");
      } else {

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now here comes the main thing:
//
        // check for one char options
        while ( char option = *++argv[i] ) {

          switch ( option ) {
          case '?':
            // Show program usage

            logInfo(L"Options:");
            logInfo(L"  /q\t>Quite mode");
            logInfo(L"  /v\t>Verbose mode");
            logInfo(L"  /d\t>Debug mode");
            return false;

            // Log options
          case 'q':
            setLogLevel(LOG_ERROR);
            break;

          case 'v':
            setLogLevel(LOG_VERBOSE);
            break;

          case 'd':
            setLogLevel(LOG_DEBUG);
            break;

          default:
            logError(L"'%s' is an illegal command line option!"
                      "  Use /? to see valid options!", option);
            return false;
          } // switch one-char-option
        } //while one-char-options
      }  //else one vs longer options
    } // if isArgAnOption

// 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^  So that's it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// What follows now is are some usefull extras...
//
    else {


      // the command line options seems to be a path...
      WCHAR tmpPath[MAX_PATH_LENGTH];
      mbstowcs(tmpPath, argv[i], sizeof(tmpPath));

      // check if the path is existing!
      //...

      prog->addPath(tmpPath); //Comment or remove to get a working example
      pathAdded = true;
    }
  }

  // check for parameters
  if ( !pathAdded ) {
    logError("You need to specify at least one folder to process!\n"
             "Use /? to see valid options!");
    return false;
  }

  return true;
}



int main(int argc, char* argv[]) {

  try {
    // parse the command line
    if ( !parseCommandLine(argc, argv, prog) ) {
      return 1; 
    }

// I know that sample is just to show how the nicely parse commandline Arguments
// So Please excuse more nice useful C-glatter that follows now...
  }
  catch ( LPCWSTR err ) {
    DWORD dwError = GetLastError();
    if ( wcslen(err) > 0 ) {
      if ( dwError != 0 ) {
        logError(dwError, err);
      }
      else {
        logError(err);
      }
    }
    return 2;
  }
}

#define LOG_ERROR               1
#define LOG_INFO                0
#define LOG_VERBOSE             -1
#define LOG_DEBUG               -2

/** Logging Level for the console output */
int logLevel = LOG_INFO;

void logError(LPCWSTR message, ...) {
  va_list argp;
  fwprintf(stderr, L"ERROR: ");
  va_start(argp, message);
  vfwprintf(stderr, message, argp);
  va_end(argp);
  fwprintf(stderr, L"\n");
}


void logInfo(LPCWSTR message, ...) {
  if ( logLevel <= LOG_INFO ) {
    va_list argp;
    va_start(argp, message);
    vwprintf(message, argp);
    va_end(argp);
    wprintf(L"\n");
  }
}

Bu sürümün argümanların birleştirilmesini de destekleyeceğini unutmayın: Yani / h / s -> / hs yazmak yerine işe yarayacaktır.

Buraya gönderen n'inci kişi olduğum için üzgünüm - ancak burada gördüğüm tüm bağımsız sürümlerden gerçekten memnun değildim. Peki, lib olanlar çok hoş. Bu yüzden, libUCW seçenek ayrıştırıcısı, Arg veya Getopt'u ev yapımı olanlara tercih ederim .

Değiştirebileceğinizi unutmayın:

*++argv[i]-> (++argv*)[0] daha uzun süre daha az şifreli ama yine de şifreli.

Tamam, parçalayalım: 1. argv [i] -> argv-char işaretçi alanındaki i-inci öğeye erişin

  1. ++ * ... -> argv işaretçisini bir karakter kadar iletir

  2. ... [0] -> işaretçiyi takip edecek, karakteri okuyacak

  3. ++ (...) -> parantez orada olduğundan, karakter değerini değil işaretçiyi artıracağız.

O kadar güzel ki C ##'da işaretçiler 'öldü' - çok yaşa işaretçiler !!!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.