2015-02-08 80 views
-1

注意:這不是家庭作業。我仍然是初學者。如何檢測C中的CLI特殊字符?

爲了澄清,並擴展,在我的問題:

在命令行界面,我們知道我們可以使用特殊意義的特殊字符,如擴展字符

ls -l *.c

擴展命令以抓取並列出所有帶「.c」擴展名的文件。

其他字符,如>,<,&,*和組合也可以使用。

可以說我正在製作一個C應用程序,它被稱爲findch,是查找字符的簡稱,我可以在CLI中調用它。

全部findch確實是取第一個參數的first character,並嘗試在以下參數中找到它,無論是string還是file。如果發現該字符,則報告發生的次數。如果失敗,它也會報告。

用法1:findch [character] [filename.ext]...

用法2:findch a "How many times does the letter a appear in this string?"

用法3:findch a filename.txt

問題顯示出來,當我做這樣的事情

findch * "hello, there!" findch^hello findch & hello

當我通過只是一個特殊字符時,CLI解釋它的方式和食堂與我的計劃。是否有一個我可以實施的簡單預防措施?或者這是更復雜一點,系統特定?

以下是目前的代碼。

findproto.h

/* 
//C Primer Plus 
//Chp 13 Programming Exercises 
//Problem 13-08 

************************************************************* 
Written by: JargonJunkie 
************************************************************* 

************************************ 
    set the preprocessor directives 
************************************/ 

/* 
    SET THE SWITCHES 
    ---------------- 
    To avoid conflicts while editing, and recompiling, I used a 
    "switch mechanism" to turn the function prototypes ON and OFF. 
*/ 
#ifndef ON 
# define ON 1 
#endif 

#ifndef OFF 
# define OFF 0 
#endif 

/* 
    maximum string length 
    --------------------- 
    11 //tiny 
    21 //small 
    41 //medium 
    81 //large 
    101 //extra 
    --------------------- 
    all sizes are offset by one 
    to include the null character 
*/ 
#ifndef STRLEN 
# define STRLEN 41 
#endif 

/* 
    Set the ERROR macro 
*/ 
#ifndef ERROR 
# define ERROR -1 
#endif 

/* 
    Since I use MinGW, there is no standard boolean header. 
    I have to define the bool type and create the true 
    and false constants. If the bool type exists, then 
    the bool type is not created. While my GCC is C99 compliant, 
    I prefer to use bool over _Bool which, IMO, looks awkward. 
*/ 
/* 
    Set the boolean values for the 
    variables true and false... 
*/ 
#ifndef BOOL 
# define BOOL ON 
# if BOOL 
#  define true 1 
#  define false 0 
     typedef _Bool bool; 
# endif 
#endif 

/* 
    Define the file options. 
    ------------------------ 
    These settings are used to decide whether the given 
    file extension type is a "valid" one. 
    ----------------------------------- 
    More extensions can be added by simply changing the EXTLEN macro 
    value. The strings can be found in the fcfunct.c file. 
    Keep in mind that the order of the values and string elements 
    must be the same. 
*/ 
#ifndef FILE_OPTIONS 

# define EXTLEN 9 

    enum file { 
     txt, asc, c, h, csv, html, log, xhtml, xml, 
     error = -1, missing = -2 
    }; 

    const char * extension[EXTLEN]; 

#endif 

/* 
    Prototypes make a good reference and allows the "black-box" concept 
    to stay in play. Once a function has been tested, and works, it 
    can be added to the prototype list. 
*/ 
#ifndef PROTOTYPES 
# define PROTOTYPES ON 
# if PROTOTYPES == ON 
     void string_to_lower(char * string); 
     void display_help(const char * string); 
     enum file known_file_extension(const char * filename); 
     enum file string_or_file(const char * string); 
     bool first_arg_is_char(char * string); 
     unsigned int count_char_in_string(char * arg, char * string); 
     unsigned int count_char_in_file(char * arg, char * filename); 
# endif 
#endif 

findfunct.c

//C Primer Plus 
//Chp 13 Programming Exercises 
//Problem 13-08 

#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
#include "findproto.h" 

/* 
    Initialize EXTENSION Based Keywords 
    ---------------------------------------------- 
    These keywords are used to compare against input supplied by the 
    user. If the keyword is found to be valid, the function returns 
    a value accordingly; else the function returns some type of error 
    based value. 
*/ 
const char * extension[EXTLEN] = { 
    ".txt", ".asc", ".c", ".h", 
    ".csv", ".html", ".log", 
    ".xhtml", ".xml" 
}; 

/* 
    The string_to_lower() function 
    --------------------------------------- 
    Transforms the string to lower case 
*/ 
void string_to_lower(char * string) 
{ 
    for (int index = 0; string[index]; index++) 
    { 
     if (isalpha(string[index])) 
     { 
      string[index] = tolower(string[index]); 
     } 
    } 
} 

/* 
    The display_help() Function 
    --------------------------------------- 
    Prints the help menu to the standard display 
*/ 
void display_help(const char * string) 
{ 
    putchar('\n'); 
    printf("Usage: %s [character] [filename.ext]...\n\n", string); 
    printf("This program takes a character and zero or more filenames\n" 
     "as command-line arguments.\n\n" 
     "If no arguements follow the character, the program reads from\n" 
     "the standarad input instead. Otherwise, it opens each file in\n" 
     "turn and reports how many times the character appeared in each\n" 
     "file.\n\n" 
     "The filename, and the character itself, should be reported along\n" 
     "with the count.\n\n" 
     "If a file can't be opened, the program reports that fact and continues\n" 
     "on to the next file.\n\n"); 
    printf("ALLOWED FILE EXTENSION TYPES\n" 
      ".txt .asc .c .h .html\n" 
      ".log .xhtml .dat .xml .csv\n"); 
} 

/* 
    The known_file_extension() Function 
    --------------------------------------- 
    IF a known file extension is found, return true on success. 
    ELSE return false on failure... 
*/ 
enum file known_file_extension(const char * filename) 
{ 
    enum file value = error; 

    //find the last occurring period 
    char * file_extension_type = strrchr(filename, '.');  

    if (NULL == file_extension_type) 
    { 
     value = missing; 
     return value; 
    } 

    string_to_lower(file_extension_type); 

    //find the file type 
    for (enum file type = txt; type <= xml; type++) 
    { 
     if (0 == strcmp(file_extension_type, extension[type])) 
     { 
      value = type; 
      break; 
     } 
    } 

    return value; 
} 

/* 
    Find the first argument and make sure the string is 
    only one character long. 

    If the the string is not one character long, grab 
    only the first character and replace the remaining 
    characters with the null character. 

    If the function succeeds, it returns true. 
    If the function fails, it returns false. 
*/ 
bool first_arg_is_char(char * string) 
{ 
    int length; 
    bool status = false; 

    length = strlen(string); 

    putchar('\n'); 

    if (isalpha(string[0])) 
    { 
     if (length == 1) 
     { 
      puts("Found character literal...\n"); 
      status = true; 
     } 

     if (length >= 2) 
     { 
      puts("Stripping string to first character...\n"); 

      for (int i = 1; i <= length; i++) 
      { 
       string[i] = '\0'; 
      } 

      status = true; 

      puts("Successfully modified the string...\n"); 
     } 

     if (status) 
     { 
      printf("Character literal: '%s'\n\n", string); 
     } 
    } 

    return status; 
} 

/* 
    Determine whether the given string is just a 
    string or a filename. 
*/ 
enum file string_or_file(const char * string) 
{ 
    enum file type = known_file_extension(string); 

    switch (type) 
    { 
     case missing: 
      puts("The file extension seems to be missing."); 
      puts("Assuming string is string literal.\n"); 
      return missing; 
     case error: 
      puts("Oops! An invalid file extension was used."); 
      return error; 
     default: 
      puts("Found valid file extension..."); 
      return type; 
    } 
} 

/* 
    Count the number of occurrences that the given character 
    arugment is found in the given string. 
*/ 
unsigned int count_char_in_string(char * arg, char * string) 
{ 
    unsigned int count = 0, index; 

    for (index = 0, count = 0; string[index] != '\0'; index++) 
    { 
     if (arg[0] == string[index]) 
     { 
      ++count; 
     } 
    } 

    return count; 
} 

/* 
    Count the number of occurrences that the given character 
    arugment is found in the given file. 
*/ 
unsigned int count_char_in_file(char * arg, char * filename) 
{ 
    FILE * source; 
    char ch; 
    unsigned int count, index; 

    if (NULL == (source = fopen(filename, "r"))) 
    { 
     fprintf(stderr, "Oops! The file %s failed to open...", filename); 
     return 0; 
    } 

    for (index = 0, count = 0; EOF != (ch = fgetc(source)); index++) 
    { 
     if (arg[0] == ch) 
     { 
      ++count; 
     } 
    } 

    return count; 
} 

findchar.c

//C Primer Plus 
//Chp 13 Programming Exercises 
//Problem 13-08 
/* 

************************************************************* 
Written by: JargonJunkie 
************************************************************* 
CHP 13 Problem #8 
************************************************************* 
Write a program that takes as command-line arguments a character 
and zero or more filenames. 

If no arguements follow the character, have the program read the 
standarad input. Otherwise, have it open each file in turn and 
report how many times the character appears in each file. 

The filename and the character itself should be reported along 
with the count. 

Include error-checking to see whether the number of arguments is 
correct and whether the files can be opened. If a file can't be 
opened, have the program report that fact and go on to the next 
file. 
************************************************************* 
*/ 

#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
#include "findproto.h" 

int main(int argc, char * argv[]) 
{ 
    enum file status; 
    unsigned number_of_chars = 0; 

    if (argc <= 1) 
    { 
     display_help(argv[0]); 
     return 1; 
    } 

    if (!first_arg_is_char(argv[1])) 
    { 
     puts("The first argument must be a character."); 
     return 1; 
    } 

    /* 
     Determine whether or not the string is a referenced 
     file name. 
    */ 
    for (int count = 2; count < argc; count++) 
    { 
     status = string_or_file(argv[count]); 

     switch (status) 
     { 
      case missing: 
       //assume string literal 
       number_of_chars = count_char_in_string(argv[1], argv[count]); 

       if (!number_of_chars) 
       { 
        printf("[Null Character]! The character '%s' was not found.\n", argv[1]); 
       } 

       if (number_of_chars) 
       { 
        printf("String: %s\n\n", argv[count]); 
        printf("The character '%s' was found %u time(s).\n", argv[1], number_of_chars); 
       } 

       break; 
      case error: 
       //something went wrong... 
       puts("Error! Possible invalid argument..."); 
       break; 
      case txt: 
      case asc: 
      case c: 
      case h: 
      case csv: 
      case html: 
      case log: 
      case xhtml: 
      case xml: 
       //assume string is of FILE type 
       //calculate the number of occurances 
       //for the given letter X... 
       break; 
      default: 
       //something went horribly wrong... 
       puts("Oops! Something went HORRIBLY wrong..."); 
       break; 
     } 
    } 


    return 0; 
} 

回答

2

是的,這是系統S具體取決於您使用的CLI/shell。對於大多數類似shell的unix,你可以用單引號引用這些參數,所以shell不會解釋這些特殊的結構,例如運行:

findch '*' "hello, there!" 
findch '&' "hello, there!" 

將在&*字符傳遞給你的程序作爲argv[1],而不單引號,沒有外殼解釋它們。 參見例如here欲瞭解更多信息,如果您使用bash shell。