Как найти строку в файле с помощью регулярных выражений в C? - PullRequest
4 голосов
/ 04 сентября 2010

как я могу использовать выражения Regex в программировании на 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);
 } 
}

Любая помощь будет высоко ценится.

1 Ответ

4 голосов
/ 04 сентября 2010

Вы читаете строку в 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...