在java中如何判断一个字符串是否符合四则混合运算(包括括号的),希望用正则表达式解决并给出示例代码. 希望给出四则混合运算(包括括号)的正则表达式. 并且希望给出在java中具体的代码实现. 输入:一个字符串,输出:布尔变量,如果输入的字符串是四则混合运算(带括号),就输出真,否则输出否. 小弟先谢过了!! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 带括号的比较难,不带括号的有一个public boolean isExpression(){ String reg = "(^\\d+)([\\+\\-\\*/]\\d+)+$"; String text = "23+45/90*7+8+9"; Pattern p=Pattern.compile(reg); Matcher m = p.matcher(text); while(m.find()){ return true; }return false;} 在javacc提供的example里面没有.javacc提供的example里面提供的例子中SimpleExamples过于简单,而其它例子又过于庞大.下面我以我们最常见的数学四则混合运算的文法来构造一个javacc的文法识别器.这个例子是我自己写的,十分简单,.其中还包括了文法识别同时嵌入的构建语法树Parse-Tree的代码.不过由于篇幅的原因,我并没有给出全部的代码,这里只给了javacc输入部分相关的代码.而Parse-tree就是一个普通的4叉树,3个child,1个next(平行结点),相信大家在学习数据结构的时候应该都是学过的.所以这里就省略过去了. 在大家看这些输入代码之前,我先给出它所使用的文法定义,好让大家有个清楚的框架. Expression -> Term { Addop Term } Addop -> "+" | "-" Term -> Factor { Mulop Factor } Mulop -> "*" | "/" Factor -> ID | NUM | "(" Expression "" 这里的文法可能和BNF范式有点不同.{}的意思就是0次到无限次重复,它跟我们在学习正则表达式的时候的”*”符号相同,所以,在Javacc中的文法表示的时候,{…}部分的就是用(…)*来表示. 为了让词法分析做得更简单,我们通常都不会在文法分析的时候,使用”(”,”)“等字符号串来表示终结符号,而需要转而使用LPAREN, RPAREN这样的整型符号来表示. PARSER_BEGIN(Grammar) public class Grammar implements NodeType { public ParseTreeNode GetParseTree(InputStream in) throws ParseException { Grammar parser =new Grammar(in); return parser.Expression(); } } PARSER_END(Grammar) SKIP : { " " | "\t" | "\n" | "\r" } TOKEN : { < ID: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","0"-"9"] * > | < NUM: ( ["0"-"9"] + > | < PLUS: "+" > | < MINUS: "-" > | < TIMERS: "*" > | < OVER: "/" > | < LPAREN: "(" > | < RPAREN: "" > } ParseTreeNode Expression() : { ParseTreeNode ParseTree = null; ParseTreeNode node; } { ( node=Simple_Expression() { if(ParseTree == null) ParseTree =node; else { ParseTreeNode t; t= ParseTree; while(t.next != null) t=t.next; t.next = node; } } )* { return ParseTree;} } ParseTreeNode Simple_Expression() : { ParseTreeNode node; ParseTreeNode t; int op; } { node=Term(){} ( op=addop() t=Term() { ParseTreeNode newNode = new ParseTreeNode(); newNode.nodetype = op; newNode.child[0] = node; newNode.child[1] = t; switch(op) { case PlusOP: newNode.name = "Operator: +"; break; case MinusOP: newNode.name = "Operator: -"; break; } node = newNode; } )* { return node; } } int addop() : {} { { return PlusOP; } | { return MinusOP; } } ParseTreeNode Term() : { ParseTreeNode node; ParseTreeNode t; int op; } { node=Factor(){} ( op=mulop() t=Factor() { ParseTreeNode newNode = new ParseTreeNode(); newNode.nodetype = op; newNode.child[0] = node; newNode.child[1] = t; switch(op) { case TimersOP: newNode.name = "Operator: *"; break; case OverOP: newNode.name = "Operator: /"; break; } node = newNode; } )* { return node; } } int mulop() :{} { { return TimersOP; } | { return OverOP; } } ParseTreeNode Factor() : { ParseTreeNode node; Token t; } { t= { node=new ParseTreeNode(); node.nodetype= IDstmt; node.name = t.image; return node; } | t= { node=new ParseTreeNode(); node.nodetype= NUMstmt; node.name = t.image; node.value= Integer.parseInt(t.image); return node; } | node=Simple_Expression() { return node; } } 其中SKIP 中的定义就是在进行词法分析的同时,忽略掉的记号.TOKEN中的,就是需要在做词法分析的时候,识别的词法记号.当然,这一切都是以正则表达式来表示的. 这个例子就有多个非终结符号,可以看出,我们需要为每个非终结符号写出一个过程.不同的非终结符号的识别过程中可以互相调用. 以Simple_Expression()过程为例,它的产生式是Expression -> Term { addop Term },而在javacc的输入文件格式是,它的识别是这样写的node=Term(){} ( op=addop() t=Term(){ … })* 前面说过,这里的”*”符号和正则表达式是一样的,就是0次到无限次的重复.那么Simple_Expression等于文法Term Addop Term Addop Term Addop Term … 而Addop也就相当于PLUS和MINUS两个运算符号.这里我们在写Expression的文法的时候,同时还使用了赋值表达式,因为这个和Yacc不同的时候,Javacc把文法识别完全地做到了函数过程中,那么如果我们要识别Simple_Expression的文法,就相当于按顺序识别Term和Addop两个文法,而识别那个文法,就相当于调用那两个非终结符的识别函数.正是这一点,我觉得Javacc的文法识别处理上就很接近程序的操作过程,我们不需要像YACC那样使用严格的文法表示格式,复杂的系统参数了. 关于Yacc的使用,其实比Javacc要复杂,还需要考虑到和词法分析器接口的问题,这个我会在以后细细讲到. 至于其它的文法操作解释我就不再多说了,如果要说,就是再写上十篇这样的文章也写不完.本文只能给读者们一个方向,至于深入的研究,还是请大家看javacc提供的官方文档资料. 最后 由于国外使用JAVA做项目的程序员比国内多,那么讨论JAVA技术的人员也比较多.可能来这里读我的文章的人都是C/C++程序员,但是关注其它领域同方向的技术也是可以让我们的知识领域更加宽广.关于JavaCC的讨论主要是在国际新闻组comp.compilers.tools.javacc如果大家在使用JavaCC做实际问题的时候遇到什么问题,不妨上去找找专家. 我毕业时候做毕业设计遇到过类似问题 有一个开源的很好用名字我忘了 可以把字符串的表达式计算值!甚至科学计算什么log 开发等等功能很强大你可以去找找因为那个有意个函数直接就判读符合不符和运算法则。 各位大哥,我需要带括号的啊,谢谢bobfallen(逐流),不过我要的是一个在java里面的通过它提供的正则表达式方法,构造一正则表达式,文法太深了,我就编译原理和有限自动机学的不好,有时间我绝对虚心学习了,但这赶着用啊,希望大家顶顶,再给一个带括号的正则表达式出来. 一个可以有单层括号的四则混合运算正则表达式(式子太长了,不一定完全正确,请不要bs我):楼主这可花了我不少工夫啊,至于多层括号嵌套怕是不行了(就我而言)((^\\d+\\s*)|(^\\s*\\(\\s*\\d+\\s*([\\+\\-\\*/]\\s*\\d+\\s*)+\\)\\s*))(([\\+\\-\\*/]\\s*\\d+)\\s*|([\\+\\-\\*/]\\s*\\(\\s*\\d+\\s*([\\+\\-\\*/]\\s*\\d+\\s*)+\\)\\s*))+$bobfallen(逐流)大虾的不错啊,佩服! 回复人: bobfallen(逐流) ( ) 信誉:100 写的应该不错,只是,考虑不够全面 ,首先认识数的概念,数由整数,浮点数。整数是有符号整数,无符号整数,然后就是 16进制,10进制,8进制。以及末位可以有L浮点数又有double ,float, 格式中又有e,f.至于表达式,那反倒简单,关键是数字的识别以前曾经做过,花了我一个月才写的比较全面(还仅支持C语言数据类型中 int 与 float,long,double的表示).想起来,还是痛苦的记忆. 回复人: Preamble() ( ) 信誉:100 Preamble兄,既然式子简单,就写出来给我嘛,我等得太急了,谢谢啊!!! 你用正则表达式估计是写不出来了,像我写的那个单层括号的都很麻烦,何况是多层嵌套的它最好是用递归方法调用一个带或不带单层括号表达式,但这是正则表达式无法做到的(可能行,我还不知道),还是建议用bobfallen(逐流)的方法,或者你先定义一个int型的变量作为node=0,然后在允许出现“(”的地方,node++,在允许出现“)”的地方node--,最后判断node是否为0,也就是,是否是符合四则混合运算,这其实就是和堆栈差不多思想了啊,呵呵!!goodluck!!!! 关于new Integer(Integer.MIN_VALUE)和Integer.MIN_VALUE 关于swing客户端 上传问题 [散分]分享老轮子 邮件附件发生器(自动分卷压缩) 如何传递通过Applet设置的参数 求救----Java最简单的程序运行为什么通不过? 请教JINI、JTA和CORBA是什么概念,有什么联系? 关于当前日期的显示! NullPointerException问题,急急 烂铁:Inner Class的使用? JBuilder3能否生成.exe文件,如果能如何做?(我刚用的2天) 帮我看看下面的代码,为什么编译不过关? 多线程高手请进
public boolean isExpression(){
String reg = "(^\\d+)([\\+\\-\\*/]\\d+)+$";
String text = "23+45/90*7+8+9";
Pattern p=Pattern.compile(reg);
Matcher m = p.matcher(text);
while(m.find()){
return true;
}
return false;
}
Addop -> "+" | "-"
Term -> Factor { Mulop Factor }
Mulop -> "*" | "/"
Factor -> ID | NUM | "(" Expression "" 这里的文法可能和BNF范式有点不同.{}的意思就是0次到无限次重复,它跟我们在学习正则表达式的时候的”*”符号相同,所以,在Javacc中的文法表示的时候,{…}部分的就是用(…)*来表示. 为了让词法分析做得更简单,我们通常都不会在文法分析的时候,使用”(”,”)“等字符号串来表示终结符号,而需要转而使用LPAREN, RPAREN这样的整型符号来表示. PARSER_BEGIN(Grammar) public class Grammar implements NodeType { public ParseTreeNode GetParseTree(InputStream in) throws ParseException { Grammar parser =new Grammar(in); return parser.Expression(); }
} PARSER_END(Grammar) SKIP : { " " | "\t" | "\n" | "\r" } TOKEN : { < ID: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","0"-"9"] * > | < NUM: ( ["0"-"9"] + > | < PLUS: "+" > | < MINUS: "-" > | < TIMERS: "*" > | < OVER: "/" > | < LPAREN: "(" > | < RPAREN: "" > }
ParseTreeNode Expression() : { ParseTreeNode ParseTree = null; ParseTreeNode node; } { ( node=Simple_Expression() { if(ParseTree == null) ParseTree =node; else { ParseTreeNode t; t= ParseTree; while(t.next != null) t=t.next; t.next = node; } } )* { return ParseTree;} } ParseTreeNode Simple_Expression() : { ParseTreeNode node; ParseTreeNode t; int op; } { node=Term(){} ( op=addop() t=Term() { ParseTreeNode newNode = new ParseTreeNode(); newNode.nodetype = op; newNode.child[0] = node; newNode.child[1] = t; switch(op) { case PlusOP: newNode.name = "Operator: +"; break; case MinusOP: newNode.name = "Operator: -"; break; } node = newNode; } )* { return node; } } int addop() : {} { { return PlusOP; } | { return MinusOP; } } ParseTreeNode Term() : { ParseTreeNode node; ParseTreeNode t; int op; } { node=Factor(){} ( op=mulop() t=Factor() { ParseTreeNode newNode = new ParseTreeNode(); newNode.nodetype = op; newNode.child[0] = node; newNode.child[1] = t; switch(op) { case TimersOP: newNode.name = "Operator: *"; break; case OverOP: newNode.name = "Operator: /"; break; } node = newNode; } )* { return node; } } int mulop() :{} { { return TimersOP; } | { return OverOP; } } ParseTreeNode Factor() : { ParseTreeNode node; Token t; } { t= { node=new ParseTreeNode(); node.nodetype= IDstmt; node.name = t.image; return node; } | t= { node=new ParseTreeNode(); node.nodetype= NUMstmt; node.name = t.image; node.value= Integer.parseInt(t.image); return node; } | node=Simple_Expression() { return node; } } 其中SKIP 中的定义就是在进行词法分析的同时,忽略掉的记号.TOKEN中的,就是需要在做词法分析的时候,识别的词法记号.当然,这一切都是以正则表达式来表示的. 这个例子就有多个非终结符号,可以看出,我们需要为每个非终结符号写出一个过程.不同的非终结符号的识别过程中可以互相调用. 以Simple_Expression()过程为例,它的产生式是Expression -> Term { addop Term },而在javacc的输入文件格式是,它的识别是这样写的node=Term(){} ( op=addop() t=Term(){ … })* 前面说过,这里的”*”符号和正则表达式是一样的,就是0次到无限次的重复.那么Simple_Expression等于文法Term Addop Term Addop Term Addop Term … 而Addop也就相当于PLUS和MINUS两个运算符号.这里我们在写Expression的文法的时候,同时还使用了赋值表达式,因为这个和Yacc不同的时候,Javacc把文法识别完全地做到了函数过程中,那么如果我们要识别Simple_Expression的文法,就相当于按顺序识别Term和Addop两个文法,而识别那个文法,就相当于调用那两个非终结符的识别函数.正是这一点,我觉得Javacc的文法识别处理上就很接近程序的操作过程,我们不需要像YACC那样使用严格的文法表示格式,复杂的系统参数了. 关于Yacc的使用,其实比Javacc要复杂,还需要考虑到和词法分析器接口的问题,这个我会在以后细细讲到. 至于其它的文法操作解释我就不再多说了,如果要说,就是再写上十篇这样的文章也写不完.本文只能给读者们一个方向,至于深入的研究,还是请大家看javacc提供的官方文档资料. 最后 由于国外使用JAVA做项目的程序员比国内多,那么讨论JAVA技术的人员也比较多.可能来这里读我的文章的人都是C/C++程序员,但是关注其它领域同方向的技术也是可以让我们的知识领域更加宽广.关于JavaCC的讨论主要是在国际新闻组comp.compilers.tools.javacc如果大家在使用JavaCC做实际问题的时候遇到什么问题,不妨上去找找专家.
有一个开源的很好用名字我忘了
可以把字符串的表达式计算值!甚至科学计算什么log 开发等等功能很强大你可以去找找
因为那个有意个函数直接就判读符合不符和运算法则。
楼主这可花了我不少工夫啊,至于多层括号嵌套怕是不行了(就我而言)
((^\\d+\\s*)|(^\\s*\\(\\s*\\d+\\s*([\\+\\-\\*/]\\s*\\d+\\s*)+\\)\\s*))(([\\+\\-\\*/]\\s*\\d+)\\s*|([\\+\\-\\*/]\\s*\\(\\s*\\d+\\s*([\\+\\-\\*/]\\s*\\d+\\s*)+\\)\\s*))+$bobfallen(逐流)大虾的不错啊,佩服!
首先认识数的概念,
数由整数,浮点数。整数是有符号整数,无符号整数,然后就是 16进制,10进制,8进制。
以及末位可以有L
浮点数又有double ,float, 格式中又有e,f.至于表达式,那反倒简单,关键是数字的识别
以前曾经做过,花了我一个月才写的比较全面(还仅支持C语言数据类型中 int 与 float,long,double的表示).想起来,还是痛苦的记忆.
Preamble兄,既然式子简单,就写出来给我嘛,我等得太急了,谢谢啊!!!
它最好是用递归方法调用一个带或不带单层括号表达式,
但这是正则表达式无法做到的(可能行,我还不知道),
还是建议用bobfallen(逐流)的方法,
或者你先定义一个int型的变量作为node=0,然后在允许出现“(”的地方,
node++,在允许出现“)”的地方node--,最后判断node是否为0,
也就是,是否是符合四则混合运算,这其实就是和堆栈差不多思想了啊,呵呵!!
goodluck!!!!