获取带有数学表达式的String,将其解析为函数式数学表达式以便稍后对其进行求值(Java)

时间:2012-06-20 20:23:37

标签: java string parsing

我将此作为服务器响应:

"[(sin(1+3*4)+2)/7]+10"

这个响应意味着1,3,4,2,7和10是DB(mysql)上的某种索引项,我需要对它进行很多次的评估。 我在java中寻找一个好的lib,我发现exp4j,expr,jep和jeval就像一个数学表达式解析器,但是我没有看到获取那些“索引”的选项,因为服务器只是给了我那个字符串但是不要给我我需要在我的数据库中查询的“索引项目”。 请帮忙:(

额外: 1,3,4,2,7和10是变量,我需要得到它(并不总是数字)因为这些变量名是我在DB中的索引。当我得到名称时,我创建了一个sql查询来获取变量的实际值。

就像这样......

ParseMath function = new ParseMath("[(sin(1+3*4)+2)/7]+10");
String[] variables = function.getVariables();

System.out.println(values) = 1, 3, 4, 2, 7, 10

后来......

String[] realValues = SqlQuery(variables);

for(int i=0; i<variables.lenght(); i++){
function.setValue(variable[i],realValue[i]);
}

double result = function.exec();

PS:我写的函数和方法不存在,我只是把它作为我的问题的上下文......

2 个答案:

答案 0 :(得分:2)

大多数表达式解析器会将数字视为数字。如果您希望将它们视为变量,请用字母替换或加上前缀,即执行以下操作:

ParseMath function = new ParseMath(replaceVariables("[(sin(1+3*4)+2)/7]+10"));

其中replaceVariables将是这样的:

String replaceVariables(String expr) {
  StringBuilder sb = new StringBuilder();
  boolean wasDigit = false;
  for (int i = 0; i < expr.length; i++) {
    char c = sb.charAt(i);
    if (c >= '0' && c <= '9') {
      if (!wasDigit) {
        sb.append('x');
      }
      wasDigit = true;
    } else if (c == '[') {
      c = '(';
    } else if (c == ']') {
      c = ')';
    }
    sb.append(c);
  }
  return sb.toString();
}

这应该将示例表达式转换为((sin(x1+x3*x4)+x2)/x7)+x10,它更有可能被表达式解析器识别。

请注意,在设置变量时需要进行相同的转换,即如果服务器响应在String数组realValues中,则需要执行与此类似的操作来设置它们:

for (int i = 0; i < realValues.length; i++) {
  function.setValue("x" + i, Double.parseDouble(realValues[i]));
}
double result = function.exec();

答案 1 :(得分:0)

我的正则表达式有点生疏,但我认为这是最有效的方法。正则表达式将为您提供表达式中变量和数字的名称,然后您可以使用表达式lib为您提供的任何设施替换值。请注意,您需要知道服务器可以返回的每个函数,以便您可以将它们从结果中排除(它们看起来像变量)。

public static void main( String[] args ) {
    String expression = "[(sin(1+3*4)+2)/7]+10";
    LinkedList<String> vars = new LinkedList<>();

    Pattern p = Pattern.compile("(?:[^0-9a-zA-Z]|\\G|^)([0-9a-zA-Z]+)(?:[^0-9a-zA-Z]|$)");
    Matcher m = p.matcher( expression );

    while(m.find()) {
        vars.add( m.group( 1 ) );
    }

    for(String s : vars ) {
        // Here's where you'd filter out the functions like "sin", "cos", etc.
        System.out.println( s );
    }
}

我建议您使用一些示例对此进行测试,以确保我的正则表达式中没有任何漏洞。