1、提出问题
在C语言中有一些符号是成对匹配出现的
括号: ( ), [ ], { }, <>
引号: ‘ ‘, “ “
检查它们是否成对出现是所有编译器实现的基本功能,可用于基本的语法检查,这个问题就可通过栈来实现!
2、算法实现思路
- 从第一个字符开始扫描
- 当遇见普通字符时忽略,当遇见左符号时压入栈中
- 当遇见右符号时从栈中弹出栈顶符号
- 进行匹配
• 匹配成功:继续读入下一个字符
• 匹配失败:立即停止 ,并报错 - 结束:
• 成功:所有字符扫描完毕,且栈为空
• 失败:匹配失败或所有字符扫描完毕但栈非空
3、算法具体实现
/*
扫描字符串中的符号是否匹配
*/
bool scanner(const char *code)
{
bool ret = false;
LinkStack *stack = LinkStack_Create();
int i = 0;
while(code[i] != '\0')
{
//获取栈顶元素
char *top = (char*)LinkStack_Top(stack);
//判断是否是左值
if(isLeft(code[i]))
{
//如果栈顶为空,则直接将左值入栈
//否则,检查栈顶是否为双引号和单引号
if(top != NULL)
{
//如果不是双引号和单引号,则继续将左值入栈
//否则,不入栈,因为双引号和单引号中的任何字符都为普通字符
if(*top != '\'' && *top != '\"')
{
LinkStack_Push(stack,(LinkStackNode*)(code + i));
//入栈后执行下一次循环
i++;
continue;
}
}
else
{
LinkStack_Push(stack,(LinkStackNode*)(code + i));
}
}
//如果栈顶元素是双引号和单引号,直到code[i]也为双引号和单引号,才执行下面的isRight判断,
//否则全部跳过
if(top != NULL)
{
if((*top == '\'' && code[i] != '\'' ) || (*top == '\"' && code[i] != '\"'))
{
i++;
continue;
}
}
//如果遇到右值,便将栈顶弹出,与该右值进行匹配,匹配不成功,则代码有语法错误
if(isRight(code[i]))
{
char *c = (char*)LinkStack_Pop(stack);
if(c == NULL || !isMatch(*c,code[i]))
{
printf("%c does not match!\n", code[i]);
ret = false;
break;
}
}
i++;
}
//所有字符检查完成后,如果栈中还有剩余,则代码有问题,否则,成功!
//判断code[i] == '\0'的原因是:如果还没扫描完所有字符,那么即使栈为空,也是失败的
if( (LinkStack_Size(stack) == 0) && (code[i] == '\0'))
{
printf("Succeed!\n");
ret = true;
}
else
{
printf("Invalid Code!\n");
ret = false;
}
LinkStack_Destroy(stack);
return ret;
}
5、小结
- 当需要检测成对出现但又互不相邻的事物时,可以使用栈“后进先出”的特性
- 栈非常适合于需要“就近匹配”的场合
6、完整源码下载
文件名:scanner-1.0.tar.gz
链接: http://pan.baidu.com/s/1jGCb9XG 密码: ksec
文件名:scanner-1.1.tar.gz
链接: http://pan.baidu.com/s/1hqq1wgs 密码: 3gkt
说明:修复了由linklist.c中的List_Get()函数所引起的BUG,详情见链接!
编译步骤:
0.1 解压缩:tar -zxvf scanner-1.1.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./Scanner