Javascript:正则表达式来解析公式 [英] Javascript: Regular Expression to parse a formula

查看:132
本文介绍了Javascript:正则表达式来解析公式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究一个解析公式的函数已经有一段时间了,但是还没能使它正常工作。它似乎并不总是有用 - 它会过滤文本的某些部分但不是全部。

I have been working on a function to parse a formula for some time, but haven't been able to make it work properly. It seems to not always work - it filters some parts of the text but not all.

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。

I am not sure about any of the RegEx used in this function, hence why I am asking for help. For example, I am not sure if /(pi)/ is the right way to get the exact text "pi" and replace it with 3.141.

(我目前正在使用 eval ,但它仅用于开发)

(I am using eval at the moment, but it's merely used for development)

任何帮助表示赞赏。

修改:

我是公式尝试解析是一个用户输入公式。他/她会输入类似的内容: 2 / 0.6个foo * pi bar + sqrt(4)foobar 。我希望它去除所有非数学字母并计算其余部分。含义上述公式将被解释为(2 / 0.6)* 3.141 + Math.sqrt(4) => 12.47

The Formula I am trying to parse is a user input formula. Where he/she would type something like: 2/0.6 pcs of foo * pi bar + sqrt(4) foobar. Where I would want it to strip all the non-math letters and calculate the rest. Meaning the above formula would be interpreted as (2/0.6) * 3.141 + Math.sqrt(4) => 12.47

编辑2:

e 是一个ExtJS对象,由网格中的一个字段传递,它包含以下变量:

e is a ExtJS object, passed through by a field in a grid, it contains the following variables:

  • colIdx (int)
  • column (Ext.grid.column.Column)
  • field (string)
  • grid (Ext.grid.Panel)
  • originalValue (string)
  • record (Ext.data.Model)
  • row (css selector)
  • rowIdx (int)
  • store (Ext.data.Store)
  • value (string)
  • view (Ext.grid.View)

我目前无法让JSFiddle正常工作。

Am currently unable to get the JSFiddle to work properly.

推荐答案

这可能是更容易标记要解析的表达式。标记化时,更容易阅读该标记流并构建自己的表达式。

It's probably easier to tokenize the expression you want to parse. When tokenized it's way easier to read that stream of tokens and build your own expressions.

我在jsFiddle上放了一个可以解析你给定公式的演示

在演示中我使用了这个 Tokenizer 用于从公式构建 TokenStream 的类和标记。

In the demo I used this Tokenizer class and tokens to build a TokenStream from the formula.

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_]*');

通过定义上述标记,标记生成器可以识别公式中的所有内容。当公式

With the above tokens defined the tokenizer can recognize everything in your formula. When the formula

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

被标记化,结果将是类似于

is tokenized the result would be a token stream similar to

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)

这篇关于Javascript:正则表达式来解析公式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆