需求

        在帮人设计一款C实现的过期图书管理系统时, 给出了对借书学生姓名进行模糊查询的要求。 也即如果存储信息里有 "马飞飞" 这个人, 我们检索其子串 "马" "马飞" "飞" 等都可以检索出这个词条。从逻辑来看,这个功能很简单,只需要判断 输入串 str 目标串 target 之间是否存在串包含关系, 也即 str 是否是 target 的子串。

问题

        从思路分析来看, 这个算法应该挺容易实现的,但是你在实现的过程中会发现 中文串 英文串的模糊查询是有一定区别的。其中对英文串的判断, 我们甚至只需要使用 strstr() 函数即可完成。

        因为目的是为了判断子串和主串的包含关系, 如果函数返回了一个下标, 我们就可以由此判断输入串是目标串的子串, 也即符合模糊查询的原则,进行输出即可; 如果返回 NULL, 那么我们就可以判断输入串不是目标串的子串,不打印结果。

以上也即模糊查询的主体思路, 但是我们在使用对英文字符的方式进行判断时出现了问题, 也即输入一个中文字符 "汪" 可能会出现 "王三" "王四" "汪五" 的输出结果, 也即多打印了额外结果。

        这个问题是由于 中文字符 特殊的存储方式导致的, 一般的英文字符在字符数组中只占 1位, 但是 中文字符 占2位。 因此,我们通过英文字符按一位比较的方式会存在问题。 也即 

str[i] == target[i] 

是错误的。

        如果需要对中文字符进行判断的话, 我们就需要以 二位字符 为窗口在主串上进行滑动, 因为每两位字符代表了 一个字。 


代码

以下是我使用的部分代码, 它以全局变量结构体数组 books name 属性作为目标串, 通过输入串 str 和 目标串 books[i].name 的迭代匹配, 得到最终模糊查询的结果。代码设定滑动窗口为2进行比较, 当输入串为多个字时, 进行循环比较, 如果该字在目标串中出现 tag + 1, 如果最终的 tag 等于 输入串的字数就输出。

如:

主串: 马飞飞  target.length = 6   '马' '飞' '飞' 每个字占 2 位

输入串: 马飞   str.length = 4  '马' '飞' 每个字占 2 位

初始: tag = 0

以 2 为窗口大小进行判断

① '马' in "马飞飞"     tag++

② '飞' in "马飞飞"     tag++

if( tag ==  str.length / 2)        //有2个字, 字符数组长度应该除2再比较。

        str 是 target 的子串,输出查询结果

else

         str 不是 target 的子串

int vague(char * str,char * target){
    //中文占两位
    int i,j,tag = 0;
    for(i = 0;i < strlen(str);i+=2){
        for(j = 0;j < strlen(target);j+=2){
            if(str[i] == target[j] && str[i+1] == target[j+1])
                tag++;
        }
    }
    return tag == strlen(str) / 2 ? 1 : 0;
}


//模糊查询
void seaBookVague(char str[20]){
    int i,j;
    for(i = 0; i < bcount; i++){
        if(vague(str,books[i].name))
            print(books[i]);
    }
}

结果

books.txt

运行结果

 

 


UPDATE

这篇文章尚是我初学C语言写下的, 可能有很多纰漏, 在如今看来也是有很多问题的, 当时由于才疏学浅没考虑到, 如今再做一次更新。

核心​​为 cmpChStr() 函数, 这里设置本地环境为中文支持, 因此C语言会自动提供对中文字符的比较支持, 因此也就不需要考虑本文上述的中文字符存储规则了。故在此基础上对输入字符串 source 和目标字符串 target 进行 strstr() 判断(该函数判断source是否是target的子串), 同时如果 source == target 也成立, 这样就完成了模糊查询的功能。

在 main 函数中给出的使用方法

代码如下所示:

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


// 定义一个用于比较字符串的函数,忽略中文字符的差异
int cmpChStr(char* str1, char* str2) {
    //设置当前环境为当前系统的默认环境,以支持中文字符比较
    setlocale(LC_ALL, "");
    return strcmp(str1, str2);
}

int vagueSearch(char * source,char * target){
    if (strstr(target, source) != NULL || cmpChStr(target, source) == 0) {
        return 1;
    }
    return 0;
}


int main() {
    //source Str && target Str
    char* strings[] = {
        "中国",
        "中华人民共和国",
        "美国",
        "日本",
        "韩国",
        "英国",
        "国国"
    };
    int size = sizeof(strings) / sizeof(strings[0]);
    for(int i = 0;i < size;i++){
        if(vagueSearch("国", strings[i])){
            printf("%s\n", strings[i]);
        }
    }
    return 0;

}


OVER 

update in midnight -  2023-9-21 00:08:32

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐