public class Main {
/**
* 检查表达式是否合法,合法返回true
* @param expression 表达式支持 +、-、*、/、(、)、整数、小数、负数
* @return
*/
private boolean checkExpression(String expression) {
//去除空格
expression = expression.replaceAll(" ","");
// 支持的运算符
Set<Character> operate_set = new HashSet<>();
operate_set.add('-');
operate_set.add('+');
operate_set.add('*');
operate_set.add('/');
//拆分字符串
char[] arr = expression.toCharArray();
int len = arr.length;
//前后括号计数,用来判断括号是否合法
int checkNum = 0;
//数字集合
List<Character> digit_list = new ArrayList<>();
//循环判断
for (int i = 0; i < len; i++) {
if(Character.isDigit(arr[i]) || arr[i] == '.'){ //数字和小数点判断
//把数字和小数点加入到集合中,为了下一步判断数字是否合法
digit_list.add(arr[i]);
}else { //非数字和小数点
//如果集合中有值,取出来判断这个数字整体是否合法
if(digit_list.size() > 0) {
//判断字符串是否合法
boolean result = isNumberStringFromList(digit_list);
if(result){
//如果合法,清空集合,为了判断下一个
digit_list.clear();
}else{
//不合法,返回false
return false;
}
}
if (arr[i] == '+' || arr[i] == '*' || arr[i] == '/') {
//判断规则(1.不能位于首位 2.不能位于末尾 3.后面不能有其他运算符 4.后面不能有后括号)
if (i == 0 || i == (len - 1) || operate_set.contains(arr[i + 1]) || arr[i + 1] == ')') {
return false;
}
} else if (arr[i] == '-') {
//减号判断规则(1.不能位于末尾 2.后面不能有其他运算符 3.后面不能有后括号)
if (i == (len - 1) || operate_set.contains(arr[i + 1]) || arr[i + 1] == ')') {
return false;
}
} else if (arr[i] == '(') {
checkNum++;
//判断规则(1.不能位于末尾 2.后面不能有+,*,/运算符和后括号 3.前面不能为数字)
if (i == (len - 1) || arr[i + 1] == '+' || arr[i + 1] == '*' || arr[i + 1] == '/' || arr[i + 1] == ')'||(i != 0 && Character.isDigit(arr[i-1]))) {
return false;
}
} else if (arr[i] == ')') {
checkNum--;
//判定规则(1.不能位于首位 2.后面不能是前括号 3.括号计数不能小于0,小于0说明前面少了前括号)
if (i == 0 || (i < (len - 1) && arr[i + 1] == '(') || checkNum < 0) {
return false;
}
}else{
//非数字和运算符
return false;
}
}
}
// 表达式最后是数字,走这里,如果集合中有值,取出来判断这个数字整体是否合法
if(digit_list.size() > 0) {
//判断字符串是否合法
boolean result = isNumberStringFromList(digit_list);
if(result){
//如果合法,清空集合,为了判断下一个
digit_list.clear();
}else{
//不合法,返回false
return false;
}
}
//不为0,说明括号不对等,可能多前括号
if(checkNum != 0){
return false;
}
return true;
}
/**
* 校验字符串是否是数值
* @param list 由数字字符组成的字符列表
* @return
*/
private boolean isNumberStringFromList(List<Character> list){
if(CollectionUtils.isEmpty(list)){
return false;
}
//正则判断数字是否合法
boolean result = isNumber(list.stream().map(Object::toString).collect(Collectors.joining()));
if(!result){
// numStr不是一个合法的数字,记录日志
}
return result;
}
/**
* 判断字符串是否为整数,浮点数类型,是返回true
* @param str
* @return
*/
public static boolean isNumber(String str){
// ? 匹配前面的子表达式零次或一次
// \d 匹配一个数字字符
// * 匹配前面的子表达式零次或多次
// + 匹配前面的子表达式一次或多次
Pattern pattern = Pattern.
compile("^-?([1-9]\\d*\\.\\d+|0\\.\\d*[1-9]\\d*|[1-9]\\d*|0)$");
Matcher isNum = pattern.matcher(str);
return isNum.matches();
}
public static void main(String[] args) {
Main main = new Main();
String[] arr = new String[]{
"2+2.",
"2+000.3",
"2+0023",
"2+a",
"2)+1",
"+2-3",
"2+(3",
"2+4)",
"2+6/",
"2+6+",
"2+6*",
"2+()+3",
"2+(3+3)+8)+9",
"100",
"1+2",
"(1+2)",
"1.2",
"1+1.2",
"(1+1.2)",
"1+(1+2)",
"1+(1+2)*2",
"1+(1+1.2)",
"1+(1+1.2)*2",
"(1+(1+1.2)*2)/2",
"(1+(1+1.2)*2)*2",
"(1+(1+1.2)*2)*(2+2)",
"(1+(1+1.2)*2)*(2+2*3+20)",
"(0.333)",
"2+(-0.3)",
};
for (String s : arr) {
System.out.println(s + " " + main.checkExpression(s));
}
// String exp = "(L1+T10)/2+1.20+M3";
// List<String> params = Lists.newArrayList("L1", "T10", "M3");
// for (String param : params) {
// exp = exp.replaceAll(param, "1");
// }
// System.out.println(exp);
//
// System.out.println(exp + " " + main.checkExpression(exp));
}
}