模式字符串查找(支持通配符‘*’)

模式字符串查找(支持通配符‘*’)

【问题描述】

在当前目录下的文件string.in中查找给定的字符串,并将查找到的字符串和行号输出到当前目录下的文件string.out中。要求:

1)从键盘输入给定的字符串,该字符串中只包含大小写字母、数字字符、中括号字符'['和']'、'*',以及字符'^'。字符串的长度不超过20。
2)字符'^'只能出现在中括号内,且只能作为中括号内的第一个字符出现。除了字符'^',中括号中至少包含一个以上的字母或数字。
3)字符*不会出现在中括号内
4)在给定字符串中,中括号最多出现一次。若中括号内未出现字符'^',表示该位置上的字符只要与中括号内的任一字符相同,则匹配成功;
   若中括号内出现字符'^',表示该位置上的字符与中括号内的所有字符都不相同时,匹配成功。
5)字符*可以同零个字符或者多个任意字符相匹配
6)在给定的字符串中,*号最多仅出现一次
7)*号的作用范围局限于一行,不会跨越行进行匹配
8) 有多个字符串和*号匹配时,仅仅输出一个,并且输出这些串中长度最短的那个
9)查找字符串时大小写无关。
10)先输出查到的行号(行号从1开始),行号后跟冒号':',然后是查找到的字符串,多个字符串之间用逗号','隔开。各行之间用一个回车换行符隔开。

【输入形式】

首先从标准输入(键盘)读入待查找的字符串。待查找的文件string.in位于当前目录下。

【输出形式】

将查找到的结果输出到当前目录下的string.out中。

【样例输入1】

zh[ao]ng

假如string.in文件内容为:

Zhang ying ju zhu zai ZhongGuo. 
Ta zheng zai du gao zhong.
Bie ren dou jia ta xiao zhang.

【样例输出1】

string.out文件内容为:

1:Zhang,Zhong
2:zhong
3:zhang

【样例1说明】

给定字符串中有中括号,表示第三个字符可以是a也可以是o,且大小写无关,因此文章中第一行的Zhang和Zhong与给定字符串匹配,故输出1:Zhang,Zhong。其它类推。

【样例输入2】

a[^ab]a

string.in文件内容为:

Do you like banana?
ABA is the abbreviation of American Bankers Association.

【样例输出2】

string.out文件内容为:

1:ana,ana

【样例2说明】

给定字符串中括号内有字符’^’,表示第一个和第三个字符都为a,第二个字符不能为a或b,因此文章中第一行的banana内有两个字符串ana与给定字符串匹配,故输出1:ana,ana。第二行中ABA的第二个字符为B,由于大小写无关,与给定字符串中括号内的b相同,故不能匹配。

【样例输入3】

w*d

string.in文件内容为:

wwwdd
world is a nice word

【样例输出3】

string.out文件内容为:

1:wwwd,wwd,wd
2:world,word

【样例3说明】

给定的字符串中有’*’,表示在一行内,可以和以’w’开头,以’d’结尾的任意字符串相匹配。在一行中,对于第一个字符’w’,同时有字符串"wwwd"以及"wwwdd"与之相匹配,根据上述第8条规则,应该匹配"wwwd"。一次类推得到’wwd’和’wd’。同样的规则用于第二行,得到"world"和"word"

【评分标准】

共有5个测试点。提交程序名为find.c。

分析

  • 本题的逻辑较为复杂,难度比较大但是也还好,因此主要问题是厘清中间的逻辑关系与情况,一点一点分布实现功能。
  • 首先本题的实现思路是:由于最多只会匹配一行的数据,因此可以用循环将数据从文件读出,一行一行匹配判断,每一行逐字符判断,通过匹配函数的返回值查看是否匹配成功,成功则将匹配到的数据存入文件,如果失败,则判断下一个字符。
  • 对于匹配函数,大致思路是遍历读入串、输入串,大致分三大种情况,也就是输入串遍历到的是字母、‘*’、‘[’,第一种情况可以直接比较两串当前位置字母是否相同;第二种情况是可以匹配任何字符,这种较为简单;第三种是‘[’,这种情况我是先将‘[’后面的字符串读出,一直读到‘]’结束,然后根据读出的这个片段判断,其中有没有出现‘^’,相应地判断读入串的字符是否符合条件。

代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <ctype.h>  //toupper(c)  tolower('A') 转换字符大小写
//获得中括号中的字符串
void getPiece(char str[], char piece[], int pos)
{
	int i = 0;
	while (str[pos] != ']') {
		piece[i++] = str[pos++];
	}
}
//判断字符c是否在字符串str中出现
int isin(char str[], char c)
{
	int i;
	for (i = 0; i < strlen(str); i++) {
		if (toupper(c) == toupper(str[i]))
			return 1;
	}
	return 0;
}
//匹配字符串
int match(char str_in[], char str_scan[], char str_out[], int pos_in_start)
{
	int pos_in = pos_in_start, pos_scan = 0, pos_out = 0;   //三个字符串中的当前字符位置
	int pos_in_end = strlen(str_in);//pos_in < pos_in_end
	while (pos_in < pos_in_end) {   //最多将读入串遍历完
		if (str_scan[pos_scan] == '*') {  //匹配到了‘*’
			if (pos_scan == strlen(str_scan) - 1)   //输入串中‘*’为最后一个字符
				while (pos_in < pos_in_end)   //将读入串中剩余字符全部存入写入串
					str_out[pos_out++] = str_in[pos_in++];
			else {   //输入串中‘*’不是最后一个字符
				while (pos_in < pos_in_end && toupper(str_in[pos_in]) != toupper(str_scan[pos_scan + 1]))  //循环到读入串与‘*’后一个字符匹配
					str_out[pos_out++] = str_in[pos_in++];
				if (pos_in == pos_in_end) return 0;   //如果是因为读入串被遍历完,匹配失败
				pos_scan++;   //跳过‘*’
			}
		}
		else if (str_scan[pos_scan] == '[') {   //匹配到‘[’
			char piece[50] = { '\0' };   //储存‘[’内的字符串
			getPiece(str_scan, piece, ++pos_scan);    //获得‘[’内的字符串
			int flag = isin(piece, str_in[pos_in]);   //判断读入串当前字符是否在中括号内出现过
			if ((piece[0] == '^' && flag) || (piece[0] != '^' && !flag)) return 0;
			str_out[pos_out++] = str_in[pos_in++];
			pos_scan += strlen(piece) + 1;   //跳过中括号
		}
		else {   //匹配到字母
			if (toupper(str_in[pos_in]) != toupper(str_scan[pos_scan]))   //不匹配
				return 0;
			str_out[pos_out++] = str_in[pos_in++];
			pos_scan++;
		}
		if (pos_scan == strlen(str_scan)) return 1;   //输入串被遍历完,匹配成功
	}
	return 1;
}

int main()
{
	char str_scan[100], str_in[1000];
	int line = 0, i;
	FILE* fin = fopen("string.in","r"), * fout=fopen("string.out","w");
	if (!fin || !fout) exit(1);
	scanf("%s", str_scan);  //获得输入串
	while (fgets(str_in, 100, fin)) {  //获得读入串
		line++;   //读入串的行数
		int flag = 1;
		strcpy(str_in, str_in);
		for (i = 0; str_in[i] != '\0'; i++) {
			char str_out[100] = { '\0' };  //输出串
			if (match(str_in, str_scan, str_out, i)) {  //匹配成功则输入到文件
				if (flag) fprintf(fout, "%d:", line);
				else fprintf(fout, ",");
				fprintf(fout, "%s", str_out);
				flag = 0;
			}
		}
		if (!flag) fprintf(fout, "\n");
	}
	fclose(fin);
	fclose(fout);
	return 0;
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谛凌

本人水平有限,感谢您支持与指正

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值