[先说点出题背景]
这个题是为低年级同学、学C语言的同学准备的,因为,对这部分同学,这个题目编写起来略有一点复杂。如果是高年级、学过了正则表达式(Regular Expression)的同学或者学过了Java等OO语言的同学做这个题,应当发现这题比较简单吧。哦,对了,什么是tokenizer?请自行查询解决。反正在此处不应翻译成“令牌解析器”。
[正题]
四则运算表达式由运算数(必定包含数字
,可能包含正或负符号
、小数点
)、运算符(包括+
、-
、*
、/
)以及小括号((
和)
)组成,每个运算数、运算符和括号都是一个token(标记)。现在,对于给定的一个四则运算表达式,请把她的每个token切分出来。题目保证给定的表达式是正确的,不需要做有效性检查。
输入格式:
在一行中给出长度不超过40个字符的表达式,其中没有空格,仅由上文中token的字符组成
输出格式:
依次输出表达式中的tokens,每个token占一行。
输入样例:
32*((2-2)+5)/(-15)
输出样例:
32
*
(
(
2
-
2
)
+
5
)
/
(
-15
)
代码:
#include<stdio.h>
#include<string.h>
void move(char a[])
// 作用是把输入的字符串往后移一个单位,然后把第0个元素替换为-1
{
int len = strlen(a);
for (int i = len; i >= 1; i--)
{
a[i] = a[i - 1];
}
a[0] = -1;
}
int judge(char ch)
// 判断字符的类型,分为运算数和符号两大类, 运算数(包括小数点)——>0
// 符号可以细分为 正负号——>1 乘除和右括号)——>2 左括号(——>3
{
if ((ch <= '9' && ch >= '0') || ch == '.') return 0;
if (ch == '+' || ch == '-') return 1;
if (ch == '*' || ch == '/' || ch == ')') return 2;
if (ch == '(') return 3;
else return -1; // 其他类返回-1(为了第0个字符特别准备
}
int main()
{
char str[50] = {0};
scanf("%s", str); move(str); // 输入和转化
int len = strlen(str);
for (int i = 1; i < len; i++)
{
int judge_this = judge(str[i]); // 分别判断此字符,上一个字符,下一个字符的类型
int judge_next = judge(str[i + 1]);
int judge_before = judge(str[i - 1]);
printf("%c", str[i]);
// 以下是重点
// 运算数——>0 正负号——>1 乘除和右括号)——>2 左括号(——>3 其他类返回-1
// 乘除和括号自己就是一个token,不可能与后来的字符组成别的token,直接打印回车
if (judge_this == 2 || judge_this == 3) printf("\n");
// 运算数后必须要跟着运算数才能组成一个token,否则回车
if (judge_this == 0 && judge_next != 0) printf("\n");
// 加减号如果上一个字符是左括号 或者 是第一个字符 才可能跟后面的数字(后面一定是数字) 组成token
// 之前定义的 move 把字符串向后移动一位的作用就在这
if (judge_this == 1 && (judge_before != 3 && judge_before != -1)) printf("\n");
}
return 0;
}
总结:
因为题目说输入都是合法的,所以小数点必定不会出现在运算数的结尾
本题的难点判断在+-号上,到底是运算符还是正负号
如何判断:
如果孤零零的在开头,肯定是正负号
如果不在开头,但是前面是左括号,也是正负号
其他情况都是运算符