如何在C中实现多关键字搜索?

时间:2019-06-17 20:36:18

标签: c performance search

我想实现不区分大小写的文本搜索,该文本搜索支持对多个关键字进行并行测试。我已经能够以某种方式实现此目标,这对我而言似乎在效率方面并不高效。

在搜索一个关键字时,函数“ strcasestr”(Link to Linux man page)似乎做得很好,但是当您想同时测试多个关键字时(据我所知),您希望迭代该关键字的字符。文本(Haystack)仅一次找到一个关键字(Needles)。

多次使用“ strcasestr”会导致-据我了解-对文本(Haystack)进行多次迭代,这可能不是最快的解决方案。一个例子:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>

int main (void) {

  // Text to search in
  char *str = "This is a test!";

  char *result = strcasestr(str, "not_found1");

  if (result == NULL) {
    result = strcasestr(str, "NOT_FOUND2");
  }

  if (result == NULL) {
    result = strcasestr(str, "TEST!");
  }

  printf("Result pointer: %s\n", result );

  return 0;
}

有没有一种方法可以以比我更快的方式获取文本中(不区分大小写)一个关键字首次出现的位置?

如果解决方案可以扩展,我将不胜感激,因为我正在进行全文搜索,因此我可以继续遍历文本以查找出现关键字的所有位置与结果评分系统。也很欢迎我向正确的方向发展的框架和小提示。

1 个答案:

答案 0 :(得分:0)

经过长时间的学习和测试,我找到了一个对我来说很好的解决方案。我测试了它的一个关键字版本,其性能可与功能“ strcasestr”(经过约500 MB的文本测试)相媲美。

解释以下代码的作用:

首先定义文本(Haystack)和关键字(Needles)。然后,这些关键字已经转换为小写字母,以获得良好的效果。 iter 是一个数字数组,反映了当前文本进度与每个关键字匹配的字符数。该程序线性地遍历 text 的每个字符,直到找到其中一个关键字的匹配项为止-在这种情况下,该程序结束并且结果为“ True”。如果未找到匹配项(= 0),则结果为“ False”。

我欢迎注释中的提示,以提高代码质量或性能。

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

int main (void) {

  int i, j;
  int match = 0;

  // Haystack
  char *text = "This is a test!";

  // Needles
  int keywords_len = 3;
  char keywords[][12] = {
    "not_found1",
    "NOT_FOUND2",
    "TEST!"
  };

  // Make needles lowercase
  for (i = 0; i < keywords_len; i++)
    for (j = 0; keywords[i][j]; j++)
      keywords[i][j] = tolower(keywords[i][j]);

  // Define counters for keywords matches
  int iter[] = { 0, 0, 0 };

  // Loop over all characters and test match
  char ptext;
  while (ptext = *text++)
    // Compare matches
    // NOTE: (x | 32) means case-insensitive
    if (!match)
      for (i = 0; i < keywords_len; i++)
        if ((ptext | 32) == keywords[i][iter[i]]) {
          if (keywords[i][++(iter[i])] == '\0') {
            match = 1;
            break;
          }
        } else
          iter[i] = 0;
    else
      break;

  printf("Result: %s\n", match ? "True" : "False");

  return 0;
}