检查结构元素并将其与 C 中的用户输入进行比较

Checking and comparing structure elements to a user input in C

我正在尝试用 C 编写一个函数,该函数 在包含客户信息的数据库中搜索 比较 某些用户的信息输入,并最终根据依赖于 Livenshtein 距离百分比的条件打印出良好的结果。

typedef struct Person_t
{
    char Name[32];
    char Email[64];
    char City[96];
    char Country[64];
} Person;  

问题来了,用户被要求输入结构成员所代表的每一个信息,但他只能输入他想要的,例如:姓名:Emily,电子邮件:(没有用户输入又名左空),城市:(留空),国家:法国。

这里的目标是仅将这些属性(Emily、Country)与数据库中的相应属性进行比较,因为:正如我所说,比较算法基于与 Livenshtein 距离相关的条件,如果该条件没有通过 50,它不会将搜索验证为“好结果”,这可能会排除好的情况,比如:

姓名:杰克,电子邮件:jack.jack@gmail.com,城市:伯明翰,国家:美国

这个客户存在于我们的“大”数据库中(假设我们有很多 Jacks 和很多来自伯明翰的人),而 smbd 进行搜索时只知道一些关于 Jack 的信息,所以他输入:

姓名:Jackk,电子邮件:(空),城市:(空),国家:美国ss

(我故意打乱拼写是为了展示 LD 的用处,它仍然会在百分比上得分很高所以不要担心)

使用 LD 的百分比条件:percentage = (1 - LD/max(string1, string2)) * 100 ,我们将截止值设置为 50%。

这里的问题是,如果我们将每个结构成员与其对应的结构成员(与用户输入的内容相关的成员)进行比较,我们将减少 它获得高百分比的可能性,因为将空字符串与“存在的”字符串进行比较会使 Livenshtein 距离很大,因此百分比 这会带走很多好的结果。

请务必注意,我不想使用 OR 。我不知道如果他得到正确的“杰克”,它将通过(百分比 = 100),由于存在太多杰克(我们正在谈论一个大数据库),这将不会有效,所以我肯定会使用 AND,以确保所有用户输入都尽可能接近他想要的,同时尽量减少结果的数量。

请记住,除此之外,post-搜索结果将根据百分比进行排序,因此需要彻底处理空白字符串。

这是我的评论的一个例子。

compare_field 函数 returns 1 如果存在有效匹配并填充 percentage out 参数;如果该字段无关紧要,它 returns 0。

compare_record 函数调用该函数 4 次,每个字段一次,并对字段比较函数返回的百分比进行平均。

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

typedef struct Person_t {
  char Name[32];
  char Email[64];
  char City[96];
  char Country[64];
} Person;

static Person database[] = {
    {.Name = "Emily",
     .Email = "emi@x.ly",
     .City = "Paris",
     .Country = "France"},
    {.Name = "Jack",
     .Email = "jack.jack@gmail.com",
     .City = "Birmingham",
     .Country = "United States"},
    {.Name = "Jank",
     .Email = "jankjank@gmail.com",
     .City = "London",
     .Country = "United Kingdom"},
};

static int compare_field(const char *record, const char *query,
                         float *percentage) {
  if (strlen(record) == 0 || strlen(query) == 0) {
    return 0; // Ignore this field in the search
  }
  // TODO: implement real levenshtein distance here
  int distance = 0;
  for (int i = 0;; i++) {
    if (record[i] == 0 || query[i] == 0)
      break;
    if (record[i] != query[i])
      distance++;
  }
  *percentage = (1.0f - distance / (float)strlen(record)) * 100.0f;
  return 1;
}

static float compare_record(const Person *record, const Person *query) {
  float total_match_percentage = 0, temp_percentage;
  int total_match_fields = 0;


  #define COMPARE_FIELD(field)  if (compare_field(record->field, query->field, &temp_percentage)) { total_match_percentage += temp_percentage; total_match_fields++; }

  COMPARE_FIELD(Name);
  COMPARE_FIELD(Email);
  COMPARE_FIELD(City);
  COMPARE_FIELD(Country);

  #undef COMPARE_FIELD

  return total_match_percentage / (float)total_match_fields;
}

int main() {
  int n_database = sizeof(database) / sizeof(Person);
  Person query = {.Name = "Jamk", .City = "Pondon", .Country = "United K"};
  for (int i = 0; i < n_database; i++) {
    float match = compare_record(&database[i], &query);
    printf("%s: %.2f\n", database[i].Name, match);
  }
}

使用源代码中的 query 打印出来(因为 Emily 仍然匹配 Paris 而我没有实现完整的 Levenshtein 距离算法)...

Emily: 13.33
Jack: 72.44
Jank: 86.11