2010-02-03 3 views
2

Если у меня есть:C: поиск строки в файле

const char *mystr = "cheesecakes"; 
FILE *myfile = fopen("path/to/file.exe","r"); 

Мне нужно написать функцию, чтобы определить, содержит ли myfile вхождений mystr. Может ли кто-нибудь мне помочь? Благодаря!

UPDATE: Итак, на платформе, которую мне нужно развернуть, нет memstr. Кто-нибудь знает о свободной реализации, которую я могу использовать в своем коде?

+1

Вы можете загрузить весь файл в память? –

+0

Он не слишком большой (<2MB), но я не знаю, как (у меня есть опыт около 30 минут C до сих пор) – igul222

+0

Я поставил реализацию «memmem» в свой ответ - и «memstr (mem, memlen , str) 'это просто' memmem (mem, memlen, str, strlen (str) + 1) '. – caf

ответ

9

Если вы не может соответствовать весь файл в память, и у вас есть доступ к расширению GNU memmem(), то:

  • читать столько, сколько вы можете в буфер;
  • Поиск буфера с memmem(buffer, len, mystr, strlen(mystr) + 1);
  • Отбросить всех, кроме последних strlen(mystr) символов буфера, и перенести их в начало;
  • Повторяйте до конца файла.

Если вы не имеете memmem, то вы можете реализовать его в виде простого С помощью memchr и memcmp, например, так:

/* 
* The memmem() function finds the start of the first occurrence of the 
* substring 'needle' of length 'nlen' in the memory area 'haystack' of 
* length 'hlen'. 
* 
* The return value is a pointer to the beginning of the sub-string, or 
* NULL if the substring is not found. 
*/ 
void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen) 
{ 
    int needle_first; 
    const void *p = haystack; 
    size_t plen = hlen; 

    if (!nlen) 
     return NULL; 

    needle_first = *(unsigned char *)needle; 

    while (plen >= nlen && (p = memchr(p, needle_first, plen - nlen + 1))) 
    { 
     if (!memcmp(p, needle, nlen)) 
      return (void *)p; 

     p++; 
     plen = hlen - (p - haystack); 
    } 

    return NULL; 
} 
+0

Thanks; Я закончил тем, что загрузил все это в память, а затем использовал ваш memmem для поиска иглы. – igul222

3

Поскольку нет memmem или memstr найти строку в двоичный массив (другие предложили прочитать его в памяти и использовать strstr - нет, это не сработает), вы должны прочитать его byte by byte с помощью «fgetch» ​​и написать небольшой конечный автомат, чтобы он соответствовал ему при чтении.

+0

Если вы находитесь в Linux и не заботитесь о переносимости, glibc имеет memmem. –

+0

Загрузка байта байтом может повредить производительность. Загрузите его в память, затем выполните поиск в памяти. – EvilTeach

-1
chat match = "findthis"; 
int depth = 0; 
while(not eof) 
{ 
    char ch = getonebyte(); 
    if(ch == match[depth]) 
    { 
     if (depth == strlen(match)) 
      break; 
     else 
      depth++; 
     } 
     else 
      depth = 0; 
} 

примерно (я уверен, что выключены единицами есть)

+1

Хорошая попытка. К сожалению, у этого есть крайний случай, когда он будет терпеть неудачу, если у вас есть строка поиска, например «112», а в файле у вас есть «1112» –

+0

. Я так не думаю, что я начинаю в начале строки соответствия, когда я нахожу ошибку несоответствия – pm100

+0

pm100, да, вы сбросите свой индекс иглы, но вы уже потеряли часть стога сена, который вам нужен. –

0

Вот хлопнул вместе версию. Он не имеет проверки ошибок и, вероятно, имеет ошибки переполнения. Но я думаю, что он находит нужную строку и учитывает обратный отсчет, необходимый для парных подстрок. Я сомневаюсь, что осталось более 15 ошибок.

Редактировать: В первом ответе было по крайней мере одно. Я проснулся посреди ночи и понял, что проверка назад была неправильной. Он не нашел «12123» в «1212123». Это может быть и не так, но, по крайней мере, сейчас это находит.

int main(int argc, char* argv[]) 
{ 
    FILE *fp; 
    char *find, *hist; 
    int len, pos=0, hl=0, i; 
    char c; 

    fp = fopen(argv[1], "r"); 
    find = argv[2]; 
    len = (int)strlen(find); 
    hist = malloc(len); 
    memset(hist, 0, len); 
    while (!feof(fp)) { 
     c = fgetc(fp); 
     if (find[pos++] == c) { 
      if (pos == len) { 
       printf("Found it\n"); 
       return 1; 
      } 
     } 
     else { 
      // check history buffer (kludge for backtracking) 
      if (pos > 0) { 
       pos = 0; 
       for (i = 0; i < len - 1; i++) 
        if (0 == memcmp(hist+len-i-1, find, i + 1)) { 
        // we had a mismatch, but the history matches up to len i 
        pos = i; 
       } 
      } 
     } 
     // update history buffer - this is innefficient - better as circular buffer 
     memmove(hist, hist + 1, len - 1); 
     hist[len-1] = c; 
    } 
    printf("Not found\n"); 
} 
0

Вот функция, которая будет искать строку в буфере.

Ограничения: он не обрабатывает широкие символы (в случае интернационализации). Вам нужно будет написать свой собственный код, чтобы прочитать файл в памяти. Он не найдет шаблон, если шаблон разделен между двумя считываемыми буферами.

/***************************************************** 
const char *buffer pointer to your read buffer (the larger, the better). 
size_t bufsize  the size of your buffer 
const char *pattern pattern you are looking for. 

Returns an index into the buffer if pattern is found. 
-1 if pattern is not found. 

Sample: 
    pos = findPattern (buffer, BUF_SIZE, "cheesecakes"); 
*****************************************************/ 

int findPattern (const char *buffer, size_t bufSize, const char *pattern) 
{ 
    int i,j; 
    int patternLen; 

    // minor optimization. Determine patternLen so we don't 
    // bother searching buffer if fewer than patternLen bytes remain. 
    patternLen = strlen (pattern); 

    for (i=0; i<bufSize-patternLen; ++i) 
    { 
     for (j=0; j<patternLen; ++j) 
     { 
      if (buffer[i+j] != pattern[j]) 
      { 
       break; 
      } 
     } 
     if (j == patternLen) 
     { 
      return i; 
     } 
    } 
    return -1; 
} 
Смежные вопросы