2013-05-11 123 views
3

我想标记由整数,浮点数,运算符,函数,变量和括号组成的字符串。下面的例子应该点亮的问题本质:用于复杂数学表达式的高级标记器

当前状态:

String infix = 4*x+5.2024*(Log(x,y)^z)-300.12 

期望状态:

String tokBuf[0]=4 
String tokBuf[1]=* 
String tokBuf[2]=x 
String tokBuf[3]=+ 
String tokBuf[4]=5.2024 
String tokBuf[5]=* 
String tokBuf[6]=( 
String tokBuf[7]=Log 
String tokBuf[8]=( 
String tokBuf[9]=x 
String tokBuf[10]=, 
String tokBuf[11]=y 
String tokBuf[12]=) 
String tokBuf[13]=^ 
String tokBuf[14]=z 
String tokBuf[15]=) 
String tokBuf[16]=- 
String tokBuf[17]=300.12 

所有的技巧和方法,将不胜感激。

+2

使用类似[ANTLR(http://www.antlr.org/)来定义哟语法你的表达并为它生成一个解析器。 – 2013-05-11 15:23:23

+0

yacc是另一个好工具。很可能你想要一个符号图而不是数组。 – 2013-05-11 15:28:31

+0

如果您正在构建表达式评估器,请在尝试之前使用GNU libmatheval或muParse :) – 2013-05-11 15:30:14

回答

5

使用Java流标记器。该接口是一个有点古怪,但人会使用它:

http://docs.oracle.com/javase/7/docs/api/java/io/StreamTokenizer.html

示例代码解析的请求字符串列表(你可能想直接使用标记生成器或至少使用一个对象列表,以便店面数量直接作为双人间):

public static List<String> tokenize(String s) throws IOException { 
    StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(s)); 
    tokenizer.ordinaryChar('-'); // Don't parse minus as part of numbers. 
    tokenizer.ordinaryChar('/'); // Don't treat slash as a comment start. 
    List<String> tokBuf = new ArrayList<String>(); 
    while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { 
    switch(tokenizer.ttype) { 
     case StreamTokenizer.TT_NUMBER: 
     tokBuf.add(String.valueOf(tokenizer.nval)); 
     break; 
     case StreamTokenizer.TT_WORD: 
     tokBuf.add(tokenizer.sval); 
     break; 
     default: // operator 
     tokBuf.add(String.valueOf((char) tokenizer.ttype)); 
    } 
    } 
    return tokBuf; 
} 

试运行:

System.out.println(tokenize("4*x+5.2024*(Log(x,y)^z)-300.12")); 
[4.0, *, x, +, 5.2024, *, (, Log, (, x, ,, y,), ^, z,), -, 300.12] 
+0

p.s.你可能会对我在github上的表达式解析器感兴趣:https://github.com/stefanhaustein/expressionparser – 2016-10-11 16:29:55

+0

你会想添加tokenizer.ordinaryChar('/'),因为'/'被视为EOF,并且循环将过早终止如果有斜线操作符。 – 2018-01-21 14:07:19

+0

完成。识别C++评论是否能够解决这个问题?可能最安全的是使用reset(),然后明确地设置所有内容...... – 2018-01-23 10:42:18

1

http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form
http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques,_and_Tools
算法的实施例:
步骤#1:读 '4'=>数字标记=>读取字符,直到达到非NUM符号(即 '*')。首先刚刚阅读,tokBuf [0]是一个数字标记。
步骤#2:读取'*'=>令牌表示二元运算符。
步骤#3:读取'x'。也许,一个函数符号=>将下一个标记标记为var-token。
依此类推。
下一步是评估,我猜?反向波兰语法或语法树将有所帮助...