2010-09-04 59 views
4

如何在C編程中使用正則表達式? 例如,如果我想找到一個文件中的行C編程中的正則表達式?

DAEMONS=(sysklogd network sshd !netfs !crond) 

然後打印每個守護進程在單獨的行這樣

sysklogd 
network 
sshd 
!netfs 
!crond 

這裏我做了什麼至今

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <regex.h> 
#define tofind "[a-z A-Z] $" 
int main(){ 
FILE *fp; 
char line[1024]; 
int retval = 0; 
char address[256]; 
regex_t re; 

if(regcomp(&re, tofind, REG_EXTENDED) != 0) 
    return; 

fp = fopen("/etc/rc.conf","r");//this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)" 
while((fgets(line, 1024, fp)) != NULL) { 
    if((retval = regexec(&re, address, 0, NULL, 0)) == 0) 
     printf("%s\n", address); 
} 
} 

任何幫助將不勝感激。

回答

3

您將行讀入line,因此您應該將line更改爲regexec()。您還需要考慮行尾的換行符是否會影響模式。 (這是正確使用fgets(),但請記住它使換行符結尾。)

你也應該做return -1;(或任何其他值不爲0模256),而不是一個普通的return沒有價值。另外,你應該檢查文件是否被打開;我不得不使用的替代名稱,因爲沒有這樣的文件我的機器上的/etc/rc.conf - MacOS X的

這個工作對我來說:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <regex.h> 

#define tofind "[a-z A-Z] $" 

int main(int argc, char **argv) 
{ 
    FILE *fp; 
    char line[1024]; 
    int retval = 0; 
    regex_t re; 
    //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)" 
    const char *filename = "/etc/rc.conf"; 

    if (argc > 1) 
     filename = argv[1]; 

    if (regcomp(&re, tofind, REG_EXTENDED) != 0) 
    { 
     fprintf(stderr, "Failed to compile regex '%s'\n", tofind); 
     return EXIT_FAILURE; 
    } 

    fp = fopen(filename, "r"); 
    if (fp == 0) 
    { 
     fprintf(stderr, "Failed to open file %s (%d: %s)\n", 
       filename, errno, strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    while ((fgets(line, 1024, fp)) != NULL) 
    { 
     line[strlen(line)-1] = '\0'; 
     if ((retval = regexec(&re, line, 0, NULL, 0)) == 0) 
      printf("<<%s>>\n", line); 
    } 
    return EXIT_SUCCESS; 
} 

如果您需要幫助編寫正則表達式而不是幫助編寫使用它們的C代碼,然後我們需要設計正則表達式來匹配你顯示的行。

^DAEMONS=([^)]*) *$ 

只要它如圖所示寫入,它就會匹配該行。如果你可以有「S」和「=」或「=」和「(」之間的空間,那麼你就需要適當的修改。我已經允許尾隨空白 - 人們往往馬虎,但是如果他們使用尾隨選項卡,那麼該行將不會被選中。

一旦你找到了行了,你必須把它分割成塊。你可能會選擇使用「捕捉」括號設施,或者乾脆用strchr()找到開括號,然後一個合適的技術來分離守護進程的名字 - 我會避免strtok()和可能使用strspn()strcspn()找到的話。


#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <regex.h> 

#define tofind "^DAEMONS=\\(([^)]*)\\)[ \t]*$" 

int main(int argc, char **argv) 
{ 
    FILE *fp; 
    char line[1024]; 
    int retval = 0; 
    regex_t re; 
    regmatch_t rm[2]; 
    //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)" 
    const char *filename = "/etc/rc.conf"; 

    if (argc > 1) 
     filename = argv[1]; 

    if (regcomp(&re, tofind, REG_EXTENDED) != 0) 
    { 
     fprintf(stderr, "Failed to compile regex '%s'\n", tofind); 
     return EXIT_FAILURE; 
    } 

    fp = fopen(filename, "r"); 
    if (fp == 0) 
    { 
     fprintf(stderr, "Failed to open file %s (%d: %s)\n", filename, errno, strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    while ((fgets(line, 1024, fp)) != NULL) 
    { 
     line[strlen(line)-1] = '\0'; 
     if ((retval = regexec(&re, line, 2, rm, 0)) == 0) 
     { 
      printf("<<%s>>\n", line); 
      printf("Line: <<%.*s>>\n", (int)(rm[0].rm_eo - rm[0].rm_so), line + rm[0].rm_so); 
      printf("Text: <<%.*s>>\n", (int)(rm[1].rm_eo - rm[1].rm_so), line + rm[1].rm_so); 
      char *src = line + rm[1].rm_so; 
      char *end = line + rm[1].rm_eo; 
      while (src < end) 
      { 
       size_t len = strcspn(src, " "); 
       if (src + len > end) 
        len = end - src; 
       printf("Name: <<%.*s>>\n", (int)len, src); 
       src += len; 
       src += strspn(src, " "); 
      } 
     } 
    } 
    return EXIT_SUCCESS; 
} 

一個很好的協議在那裏調試代碼的 - 但它不會帶你長,產生你要求的答案。我得到:

<<DAEMONS=(sysklogd network sshd !netfs !crond)>> 
Line: <<DAEMONS=(sysklogd network sshd !netfs !crond)>> 
Text: <<sysklogd network sshd !netfs !crond>> 
Name: <<sysklogd>> 
Name: <<network>> 
Name: <<sshd>> 
Name: <<!netfs>> 
Name: <<!crond>> 

請注意:當你想在正則表達式一個反斜槓,你必須寫在C源代碼的兩個反斜槓。

+1

只是想補充一點,正則表達式'toFind'是有缺陷的。反正什麼都不會。 – 2010-09-04 18:23:29

+0

@Jeff:你確定?如圖所示,RE找到一個單一的字母,後跟一個空白和行尾或兩個空白和行尾。解析/etc/rc.conf是否合理是一個問題 - 然而,RE會發現它想要查找的內容。 – 2010-09-04 18:36:05

+0

不過,我沒有得到任何輸出? /etc/rc。conf內容是 bla bla bla DAEMONS=(sysklogd network sshd !netfs !crond) bla bla bla Face 2010-09-04 18:51:27