1,首先讲一下java中正则表达式的坑
举例: 欲校验公式(+x+1)
合法性,正则表达式\([+\-*/]+
,使用菜鸟在线正则校验就可以匹配,而使用java的String.matches
方式竟然匹配不成功:
public static void main(String[] args) {
String express = "(+x+1)";
String regex = "\\([+\\-*/]+";
System.out.println("String matches result:" + express.matches(regex));
}
然后各种百度,终于找到了解决办法,使用以下这种方式可以正确匹配:
public static void main(String[] args) {
String express = "(+x+1)";
String regex = "\\([+\\-*/]+";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(express);
System.out.println("pattern-matcher result:" + m.find());
}
现在知道两者的区别了!!!
str.matches(String regex)
方法是检测全字符串是否匹配给定的正则表达式,此方法与Pattern.matches(regex, str)
产生的结果完全相同;
而Pattern-Matcher find 方式是在字符串中查找匹配正则,如果查找到了匹配的局部字符串,就返回true
2,需求:校验用户输入的公式是否合法
具体限制:公式中只能包含±*/()以及数字,最多只会含有一个未知数,用X表示,可以是两位小数
我的实现如下(注释写的很详细,保姆式笔记,以后忘了反复看方便记忆。如果大家有更好的更简便的方法请指教哈):
public class FormulaCheckUtil {
/**
* 验证四则运算表达式是否准确
* 注意:此处正则表达式都应【写错误形式】,而非【正确形式然后取反】,否则只要有一次匹配成功就返回true了
* @param expression 字符串公式表达式
*/
public static boolean check(String expression) {
//错误情况,小数点后最多2位
// \\.代表小数点;\\d表示数字;[]表示内部符号只出现其中一个,此处[\\d]就表示一个数字;{3,}表示前边的字符出现最少3次
if (FormulaCheckUtil.match("\\.[\\d]{3,}", expression)) {
System.out.println("公式有误!小数点后最多2位:" + expression);
return false;
}
//错误情况,小数点后边不是数字
// \\.代表小数点;\\d表示数字;[]中的^代表取反;此处[^\\d]表示非数字
if (FormulaCheckUtil.match("\\.[^\\d]", expression)) {
System.out.println("公式有误!小数点后边不是数字:" + expression);
return false;
}
//错误情况,小数点前边不是数字
//同上
if (FormulaCheckUtil.match("[^\\d]\\.", expression)) {
System.out.println("公式有误!小数点前边不是数字:" + expression);
return false;
}
//错误情况,空格前后都是数字(数字被空格分隔)
// \\d表示数字;\\s(小写字母s)表示空格;+表示前边的字符出现一次或多次
if (FormulaCheckUtil.match("\\d[\\s]+\\d", expression)) {
System.out.println("公式有误!数字不连续:" + expression);
return false;
}
String exprTrim = expression.replaceAll(" ", "").toUpperCase();
// 错误情况,空字符串
if (StringUtils.EMPTY.equals(exprTrim)) {
System.out.println("公式有误!表达式不能为空!");
return false;
}
//公式中只能包含 +-*/()X
// []中的内容依次是“取反符号、加、减、乘、除、左小括号、右小括号、数字、小数点”,
//其中“减号、左右小括号、小数点”需要转义,因此前边都有两条反斜杠,然后[]最前边是取反符号^,表示非以上字符;
// []后边的+表示前边的字符出现一次或多次
if (FormulaCheckUtil.match("[^+\\-*/\\(\\)X\\d\\.]+", exprTrim)) {
System.out.println("公式有误!公式中只能包含 +-*/()X和数字");
return false;
}
//公式中不包含X时,只支持输入数字,不支持输入运算符
if (!exprTrim.contains("X")) {
// \\d-数字 “.”-小数点 “+”-出现一次或多次
String regex = "[\\d.]+";
if (!exprTrim.matches(regex)) {
System.out.println("公式有误!公式中不包含X时,只支持输入数字!");
return false;
}
}
// 错误情况,运算符连续
// []中的“加减乘除”符号连续出现2次以上
if (FormulaCheckUtil.match("[+\\-*/]{2,}", exprTrim)) {
System.out.println("公式有误!运算符不能连续!");
return false;
}
// 空括号 \\(-转义左括号 \\)-转义有括号
if (FormulaCheckUtil.match("\\(\\)", exprTrim)) {
System.out.println("公式有误!不能含有空括号!");
return false;
}
// 错误情况,括号不配对
Stack<Character> stack = new Stack<>();
for (int i = 0; i < exprTrim.length(); i++) {
char item = exprTrim.charAt(i);
if ('(' == item) {
stack.push('(');
} else if (')' == item) {
if (!stack.isEmpty()){
stack.pop();
} else {
System.out.println("公式有误!括号不配对!");
return false;
}
}
}
if (!stack.isEmpty()) {
System.out.println("公式有误!括号不配对!");
return false;
}
// 错误情况,X连续出现两次以上
if (FormulaCheckUtil.match("X{2}", exprTrim)) {
System.out.println("公式有误!未知数不能连续出现!");
return false;
}
// 错误情况,X后面不是运算符或")"
// []内取反符号后依次为“加、减、乘、除、左括号”,表示非以上字符;表达式匹配的是“X后边非以上字符”
if (FormulaCheckUtil.match("X[^+\\-*/)]", exprTrim)) {
System.out.println("公式有误!X后面只能是运算符或\")\"");
return false;
}
// 错误情况 X前边不是"("或运算符
// []内取反符号后依次为“右括号、加、减、乘、除”,表示非以上字符;表达式匹配的是“X前边非以上字符”
if (FormulaCheckUtil.match("[^(+\\-*/]X", exprTrim)) {
System.out.println("公式有误!X前边只能是\"(\"或运算符");
return false;
}
if (exprTrim.contains("(")) {
// 错误情况,(后面是运算符
// "\\("表示左小括号;[]内依次为“右括号、加、减、乘、除”;[]后有一个+ 表示前边一个字符出现一次或多次;
// 表达式匹配的是“左括号后边是以上字符”
if (FormulaCheckUtil.match("\\([+\\-*/]+", exprTrim)) {
System.out.println("公式有误!\"(\"后面不能是运算符");
return false;
}
// 错误情况,)前面是运算符
// 同上
if (FormulaCheckUtil.match("[+\\-*/]+\\)", exprTrim)) {
System.out.println("公式有误!\")\"前面不能是运算符");
return false;
}
// 以 "(" 开头, 或者 "(" 前边是运算符,否则错误
// []内取反符号^后边依次为“左括号、加、减、乘、除”符号,[]内表达式部分表示非以上字符;“\\(”表示左括号
// 表达式含义为左括号“(”前边为 非以上字符
if (!exprTrim.startsWith("(") && FormulaCheckUtil.match("[^(+\\-*/]\\(", exprTrim)) {
System.out.println("公式有误!\"(\"前边只能是\"(+-*/\"!");
return false;
}
// 以 ")" 结尾或者 ")" 后边是运算符,否则错误
// 同上
if (!exprTrim.endsWith(")") && FormulaCheckUtil.match("\\)[^)+\\-*/]", exprTrim)) {
System.out.println("公式有误!\")\"后边只能是\")+-*/\"!");
return false;
}
}
//将“加减乘除”符号替换为同一个字符
String temp = exprTrim.replaceAll("[+\\-*/]", "`");
if (temp.startsWith("`")) {
System.out.println("公式有误!不能以运算符开头!");
return false;
}
return true;
}
private static boolean match(String regex, String express) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(express);
return m.find();
}
}
参考博客: