如何解析正弦函数?

时间:2014-01-18 08:47:53

标签: java regex string split

我的字符串输入带有sin(b(x-c))+ d作为其格式。我应该使用什么分隔符表达式来分割它,以便我可以使用Integer.parse来获取a,b,c和d的数值?

所以,如果字符串输入是

sin 5x                   a=1, b=5, c=d=0
sin 5(x-4)               a=1, b=5, c=4, d=0
2  sin 3(x-2)           a=2, b=3, c=2, d=0
sin 5x + 3               a=1, b=5, c=0, d=3
4  sin 7(x+6) + 2       a=4, b=7, c=-6, d=2
11  sin 2x              a=11, b=2, c=d=0

2 个答案:

答案 0 :(得分:2)

PUH。每当您使用字符串提供抽象上下文(如数学函数)时,您应该考虑写:
TokenScanner,用于识别您的案例中的令牌:
功能名称'罪',
operator'(',')','+'
常数代币1,2,5。
从字符串中提取令牌后,您可以开始构建AST(抽象语法树) 通过评估此树,您可以执行计算。

看,如果你从上面提到的公式中得到了数字,你会采取哪些步骤呢?操作员,数字甚至功能名称本身可以在您的公式中的不同位置,否则您将对字符串本身进行非常复杂的分析。
构建令牌扫描仪很简单 构建AST似乎更复杂,但在这种情况下不是这样,因为表达式的语法不太复杂。
因此,不是根据你期望的那种表达方式分析整个字符串,而是集中于符号如何相互关联。例如。罪(3 +(2 + 4))。
给你一个形式的AST:
功能'sin'
操作员'('
const_value 3
操作员+
操作员'('
const_value 2
操作员'+'
const_value 4
operator')'
operator')'。
然后,您可以遍历该树以获取最内层的表达式,对其进行评估并重新生成它的结果。你知道每个函数 - 调用创建一个新的范围
以及每个开放的圆括号。
因此,不难发现,哪一个是最里面的。 TokenScanner基本上可以是以下形式:
读取字符串中的第一个字符,与令牌列表进行比较,当它匹配时,构建该令牌类型的对象,读取下一个令牌,构建该令牌的对象,将两者都链接起来令牌,例如通过第一个和下一个 - 指针等等。
要获得一个基本想法:

public class TokenScanner {
    public TokenScanner() { }
    public Token scan(String input) {
      Token root = new Token();
      Token prevToken = null;

      for(int i = 0; i < input.length(),i++) {
      Token newToken = null;
      char c = input.getCharAt(i);

      switch(c) {
        case 's': //** s is the start of the word sin, and not used in other contexts in this example, so: **/
        newToken = new FunctionToken();
        break;
        case '(':
          newToken = new Expression();
        case ')':
          newToken = new Expression();
        ....
      }
      if(prevToken == null) { 
        root->next = newToken;
        newToken->prev = root;
      }
      else {
        newToken->prev = prevToken;
        prevToken->next = newToken;
      }

      return root;
      }
    }
}

public class Token() {
    public Token prev;
    public Token next;
    public int TOKEN_TYPE = 0;

    public Token() {
    }
}

public class FunctionToken extends Token {
  static public int TOKEN_TYPE = 1;
}

public class Expression extends Token {
}

public class TokenTreeVisitor {
    public void traverse(Token currentToken) {
    switch(currentToken.TOKEN_TYPE) {
      case 1:
        enter((FunctionToken) currentToken);
    }
    }
}

虽然此处已有解释令牌,但您应该将token更改为OpenBracketToken和ClosingBracketToken for tokenScanner。但它显示了如何从令牌到表达式和你可以评估的表达式。
这又是一个检查表达式是否包含子表达式的过程。如果有任何,那么进程到该子表达式。如果不是,则评估子表达式并将该表达式替换为该树中的表达式 例如
原始子表达式(5 +(1 + 7))
表达式exp仅包含const_value(1),运算符'+',const_value(7) 通过Int.parse(1)+ INt.parse(7),

评估它
class ExpressionResult extends Expression {
     public int result;
}

result = new ExpressionResult(); result->result = 8;
exp->prev->next = result; result->prev = exp->prev; result->next =  exp->next;

再次扫描并替换递归     exp2现在是const_value(5)+ operator'+'+ expression_result(8)

所以你可以Int.parse(5)+ exp2-&gt; next-&gt;结果;

等等。安静琐事,不是吗? ;)

答案 1 :(得分:1)

我认为你需要一个小的解析器。我认为你不能 只用regexp来做,但我没有试图严格证明这一点。
试试这个代码。我没有在你的所有输入上测试它但是它 应该给你一个想法。

public class Test002 {

    // private static String s = " 10 sin 5 ( x - 4 ) - 14 ";

    // private static String s = " 10 sin 2x ";

    private static String s = " -4  sin -7 (x+6) - 2 ";

    private static int i = 0;

    public static void main(String[] args){
        String str = s.replaceAll(" ", "");
        s = str;
        parseExpr();
    }

    private static void parseExpr(){
        parseA();
        parseSin();
        parseSinArgument();
        parseD();
    }

    private static void parseSinArgument(){
        parseB();
        if (s.charAt(i) == '('){
            parseOpenBracket();
            parseX();
            parseC();
            parseCloseBracket();
        }else{
            parseX();
        }
    }

    private static void parseA(){
        int j = i;
        while (s.charAt(i) != 's') i++;
        System.out.println("A=[" + getToken(j, i) + "]");
        // stay at the 's' now!
    }

    private static void parseSin(){
        int j = i;
        while (s.charAt(i) != 'n') i++;
        i++;
        // move past the 'n' now!
    }

    private static void parseB(){
        int j = i;
        while ( s.charAt(i) == '-' || Character.isDigit( s.charAt(i) )) i++;
        System.out.println("B=[" + getToken(j, i) + "]");
    }

    private static void parseOpenBracket(){
        int j = i;
        i++;
        System.out.println("OPEN_BRACKET=[" + getToken(j, i) + "]");
    }

    private static void parseX(){
        int j = i;
        while (s.charAt(i) != 'x') i++;
        i++;
        System.out.println("X=[" + getToken(j, i) + "]");
    }

    private static void parseC(){
        int j = i;
        while (s.charAt(i) != ')') i++;
        System.out.println("C=[" + getToken(j, i) + "]");
    }

    private static void parseCloseBracket(){
        int j = i;
        i++;
        System.out.println("CLOSE_BRACKET=[" + getToken(j, i) + "]");
    }

    private static void parseD(){
        int j = i;
        while (i<s.length()) i++;
        System.out.println("D=[" + getToken(j, i) + "]");
    }

    private static String getToken(int i1, int i2){
        String str = s.substring(i1, i2);
        str = str.replaceAll(" ", "");
        return str.trim();
    }

}