2013-08-27 6 views
3

수식을 구문 분석하는 함수에서 작업했지만 제대로 작동하지 못했습니다. 항상 작동하지 않는 것 같습니다. 텍스트의 일부분을 필터링하지만 전부는 아닙니다.Javascript : 수식을 구문 분석하는 정규식

parseFormula(e) { 
    var formula = e.value, value = 0.00, tValue = 0.00, tFormula = '', dObj = {}; 
    if(formula !== undefined && formula !== "") { 
     dObj._formulaIn = formula; 
     var f = formula.split(/\s/g);  

     for(var i = 0; i < f.length; i++) { 
      tFormula = f[i]; 
      // Replacing PI 
      tFormula = tFormula.replace(/(pi)/gi,Math.PI); 
      dObj._1_pi_done = tFormula; 

      // Replacing Squareroot with placeholder 
      tFormula = tFormula.replace(/(sqrt)/gi,"__sqrt__"); 
      tFormula = tFormula.replace(/(sqr)/gi,"__sqrt__"); 
      tFormula = tFormula.replace(/(kvrt)/gi,"__sqrt__"); 
      tFormula = tFormula.replace(/(kvr)/gi,"__sqrt__"); 
      dObj._2_sqrt_done = tFormula; 

      // Removing units that may cause trouble 
      tFormula = tFormula.replace(/(m2||m3||t2||t3||c2||c3)/gi,""); 
      dObj._3_units_done = tFormula; 

      // Removing text 
      tFormula = tFormula.replace(/\D+[^\*\/\+\-]+[^\,\.]/gi,""); 
      dObj._4_text_done = tFormula; 

      // Removing language specific decimals 
      if(Language.defaultLang === "no_NB") { 
       tFormula = tFormula.replace(/(\.)/gi,""); 
       tFormula = tFormula.replace(/(\,)/gi,"."); 
      } else { 
       tFormula = tFormula.replace(/(\,)/gi,"");   
      } 
      dObj._5_lang_done = tFormula; 

      // Re-applying Squareroot 
      tFormula = tFormula.replace(/(__sqrt__)/g,"Math.sqrt"); 
      dObj._6_sqrt_done = tFormula; 

      if(tFormula === "") { 
       f.splice(i,1); 
      } else { 
       f[i] = tFormula; 
      } 
      dObj._7_splice_done = tFormula; 
      console.log(dObj); 
     } 

     formula = ""; 
     for(var j = 0; j < f.length; j++) { 
      formula += f[j]; 
     } 

     try { 
      value = eval(formula); 
     } 
     catch(err) {} 
     return value === 0 ? 0 : value.toFixed(4); 
    } else { 
     return 0; 
    } 
} 

이 기능에 사용 된 RegEx에 대해서는 확실하지 않으므로, 왜 도움을 요청하고 있습니까? 예를 들어 /(pi)/이 정확한 텍스트 "pi"를 가져 와서 3.141로 바꾸는 올바른 방법인지 확신 할 수 없습니다.

감사 어떤 도움을 (나는 순간 eval를 사용하고 있지만 단지 개발을 위해 사용되는).

편집 :

내가 구문 분석하려고 수식은 사용자 입력 공식이다. 그/그녀는 다음과 같이 입력 할 것입니다 : 2/0.6 pcs of foo * pi bar + sqrt(4) foobar. 내가 수학적이지 않은 모든 글자를 떼어 내고 나머지를 계산하기를 원하는 곳에. 상기 화학식 2 (2/0.6) * 3.141 + Math.sqrt(4) =>12.47

편집하는 것으로 해석 될 의미

    : 그리드의 필드에 의해 ExtJS에 오브젝트를 통해 전달

    e, 다음과 같은 변수를 포함

  • colIdx (INT)
  • column (Ext.grid.column.Column)
  • 6,752,(문자열)
  • grid (Ext.grid.Panel)
  • originalValue (문자열)
  • record (Ext.data.Model)
  • row CSS (선택기)
  • rowIdx (INT)
  • store (Ext.data.Store)
  • value (문자열)
  • view (Ext.grid.View)가 제대로 작동하려면 JSFiddle를 얻을 현재없는

입니다.

+0

질문은 무엇인가 유사한 토큰 스트림 것입니까? – mishik

+1

이것은 Ext JS와 어떤 관련이 있습니까? –

+0

명백한 실수가있는 경우 RegExs에서 내가 뭘 잘못하고 있는지 궁금합니다. – rnngau

답변

5

구문 분석 할 표현식을 토큰 화하는 것이 더 쉽습니다. 토큰 화되면 토큰 스트림을 읽고 자신의 식을 쉽게 작성할 수 있습니다. 데모에서

I've put up a demo on jsFiddle which can parse your given formula

나는 공식에서 TokenStream를 구축하기 위해 Tokenizer 클래스와 토큰을 사용했다.

function Tokenizer() { 
    this.tokens = {}; 
    // The regular expression which matches a token per group. 
    this.regex = null; 
    // Holds the names of the tokens. Index matches group. See buildExpression() 
    this.tokenNames = []; 
} 

Tokenizer.prototype = { 
    addToken: function(name, expression) { 
     this.tokens[name] = expression; 
    }, 

    tokenize: function(data) { 
     this.buildExpression(data); 
     var tokens = this.findTokens(data); 
     return new TokenStream(tokens); 
    }, 

    buildExpression: function (data) { 
     var tokenRegex = []; 
     for (var tokenName in this.tokens) { 
      this.tokenNames.push(tokenName); 
      tokenRegex.push('('+this.tokens[tokenName]+')'); 
     } 

     this.regex = new RegExp(tokenRegex.join('|'), 'g'); 
    }, 

    findTokens: function(data) { 
     var tokens = []; 
     var match; 

     while ((match = this.regex.exec(data)) !== null) { 
      if (match == undefined) { 
       continue; 
      } 

      for (var group = 1; group < match.length; group++) { 
       if (!match[group]) continue; 

       tokens.push({ 
        name: this.tokenNames[group - 1], 
        data: match[group] 
       }); 
      } 
     } 

     return tokens; 
    } 
} 


TokenStream = function (tokens) { 
    this.cursor = 0; 
    this.tokens = tokens; 
} 
TokenStream.prototype = { 
    next: function() { 
     return this.tokens[this.cursor++]; 
    }, 
    peek: function (direction) { 
     if (direction === undefined) { 
      direction = 0; 
     } 

     return this.tokens[this.cursor + direction]; 
    } 
} 

정의 토큰 수식에 모든 것을 인식 할 수있는 토크 나이를 정의 위의 토큰으로

tokenizer.addToken('whitespace', '\\s+'); 
tokenizer.addToken('l_paren', '\\('); 
tokenizer.addToken('r_paren', '\\)'); 
tokenizer.addToken('float', '[0-9]+\\.[0-9]+'); 
tokenizer.addToken('int', '[0-9]+'); 
tokenizer.addToken('div', '\\/'); 
tokenizer.addToken('mul', '\\*'); 
tokenizer.addToken('add', '\\+'); 
tokenizer.addToken('constant', 'pi|PI'); 
tokenizer.addToken('id', '[a-zA-Z_][a-zA-Z0-9_]*'); 

. 공식

2/0.6 pcs of foo * pi bar + sqrt(4) foobar 

이 토큰 화 될 때 그 결과는

int(2), div(/), float(0.6), whitespace(), id(pcs), whitespace(), id(of), whitespace(), id(foo), whitespace(), mul(*), whitespace(), constant(pi), whitespace(), id(bar), whitespace(), add(+), whitespace(), id(sqrt), l_paren((), int(4), r_paren()), whitespace(), id(foobar) 
+0

와우, 정말 고마워! – rnngau

+0

도서관에 넣으십시오. –

+0

@AriPorad 제안 해 주셔서 감사합니다. 그것은 제가 일하고있는 개인 프로젝트의 일부입니다 .-) – Bart

0

정규 표현식을 사용하여 수식과 일치시킬 수는 없습니다. 수식은 context-free language이고 정규 표현식은 regular languages으로 제한됩니다. 후자는 전자의 하위 집합입니다. CYKLL parsers과 같은 문맥 자유 언어를 인식하기위한 알고리즘이 많이 있습니다. 이미 주제가 매우 컸기 때문에 이미 공부하지 않았다면 공부하지 않는 것이 좋습니다. 당신이 효율적이고 쉽게하지만, 신속하게 수행 할 수있는

Reverse Polish Notation (RPN)를 사용하여 식 (RPN에 수식을 변환 할 Shunting Yard algorithm를 사용)를 계산하려고하는 것입니다.시도가 실패한 경우 (괄호 안의 괄호, 잘못된 함수/상수, w/e로 인해) 텍스트가 공식이 아니므로 그렇지 않으면 모두 좋다. Shunting 야드는 특히 어려운 알고리즘이 아니므로이를 구현하는 데 문제가 없어야합니다. 비록 당신이해도 위 링크 된 위키 피 디아 페이지는 의사 코드를 가지고 있으며 당신을 도울 수있는 수많은 질문이 있습니다.

+0

감사 응답을 위해, 그러나 나는 문맥 자유로운 언어를 인식하기 위해 RegEx를 사용하려하지 않고, 사전 정의 된 호출을 사용하여 공식을 구문 분석하려고한다. 필자의 원래 생각은 SQRT에 대한 호출을 ASCII 코드로 대체하여 사용하지 않는 문자를 제거한 후 Math.sqrt로 대체하는 것이 었습니다. 또한 IF, LOG, COS, SIN, ARCSIN 등과 같은 다른 유형의 함수에도 동일한 함수를 사용하려고합니다. – rnngau

+0

그래서 Shunting yard를 사용하는 것이 좋습니다. 원하는 함수와 상수를 사용할 수 있습니다. 게다가, 이것은 널리 알려진 알고리즘이므로 구현은 다른 부분에서 특정 마법 문자열을 대체하는 것을 기반으로하는 현재의 시도보다 훨씬 오류를 발생시키지 않고 (유지 보수가 용이 한 이미지로 1 년 후에 코드를 파악해야 함) 기능. –

관련 문제