js解析字符串四则表达式

记得大学时学到过解析字符串四则表达式,好像是数据结构里的课程。具体的内容都忘掉了,也找不到数据结构课本,就在网上找了些相关资料,现在用js实现一下。具体思路是把普通的表达式转换为前置或者后置表达式,然后通过转换后的表达式来计算。

当然,是有需求了才这么做。在js中通过eval或着Function都可以实现类似功能。通过测试,在非ie浏览器中解析表达式的效率比eval(Function)高,在ie中正好相反。由于客户的大多使用的是ie,就采用了Function的方式。

代码如下:

 

(function () {
    var priority = {
        '*': 2,
        '/': 2,
        '+': 1,
        '-': 1
    }, strExpression2arrExpression = function (expression) {//字符串转换为数组
        var arr = [];
        for (var i = 0, s, t, l = expression.length; i < l; i++) {
            s = expression.charAt(i);
            if (isNaN(s)&&s!='.') {
                arr.push(s);
            } else {
                t = s;
                while (i < l) {
                    s = expression.charAt(i + 1);
                    if (!isNaN(s)||s=='.') {
                        t += s;
                        i++;
                    } else {
                        break;
                    }
                }
                arr.push(parseFloat(t));
            }
        }
        return arr;
    }, infixExpression2prefixExpression = (function () { //将中缀表达式转换为前缀表达式
        var s1 = [], s2 = [], operator = function (o) {
            var last = s1[s1.length - 1];
            if (s1.length == 0 || last == ')') {
                s1.push(o);
            } else if (priority[o] >= priority[last]) {
                s1.push(o);
            } else {
                s2.push(s1.pop());
                operator(o);
            }
        };
        return function (arrExpression) {
            s1.length = 0;
            s2.length = 0;
            for (var i = arrExpression.length - 1, o; i >= 0; i--) {
                o = arrExpression[i]
                if (!isNaN(o)) {
                    s2.push(o);
                } else {
                    if (o == '+' || o == '-' || o == '*' || o == '/') {//运算符
                        operator(o)
                    } else {//括号
                        if (o == ')') {//右括号
                            s1.push(o)
                        } else {//左括号
                            var s = s1.pop();
                            while (s != ')') {
                                s2.push(s);
                                s = s1.pop();
                            }
                        }
                    }
                }
            }
            if (s1.length > 0) {
                while (s1[0] != undefined) {
                    s2.push(s1.pop())
                }
            }
            s1.length = 0;
            return s2.slice();
        }
    })(), computePrefixExpression = (function () {
        var s1 = [], result;
        return function (prefixExpression) {
            s1.length = 0;
            //计算
            while (prefixExpression.length > 0) {
                var o = prefixExpression.shift();
                if (!isNaN(o)) {
                    s1.push(o);
                } else {
                    switch (o) {
                        case '+':
                        {
                            result = s1.pop() + s1.pop();
                            break;
                        }
                        case '-':
                        {
                            result = s1.pop() - s1.pop();
                            break;
                        }
                        case '*':
                        {
                            result = s1.pop() * s1.pop();
                            break;
                        }
                        case '/':
                        {
                            result = s1.pop() / s1.pop();
                            break;
                        }
                    }
                    s1.push(result);
                }
                //console.log(s2,s1)
            }
            //console.log(s1)
            return s1[0];
        }
    })();
    window.compute = function (expression) {
        //console.log(strExpression2arrExpression(expression))
        //console.log(infixExpression2prefixExpression(strExpression2arrExpression(expression)).reverse())
        return computePrefixExpression(infixExpression2prefixExpression(strExpression2arrExpression(expression)));
    }
})();

 

 

 

 

 

测试结果如下:

 

console.log(compute('100/(1.5+10/((2+3)*4)-5)*10'))
eval('console.log(100/(1.5+10/((2+3)*4)-5)*10)')

 

-333.33333333333337

-333.33333333333337

 

本文参考了antineutrino的文章《前缀、中缀、后缀表达式》,讲得很不错,具体原理大家可以学习一下。

有兴趣了可以看看本人的一个在线demo

 

 

 

 

 

<think>我们正在处理一个关于如何将JavaScript字符串换为正则表达式的问题。根据用户提供的引用,我们需要从引用中提取相关信息,并结合JavaScript的标准方法来实现这个换。 在JavaScript中,我们可以使用`RegExp`构造函数来将字符串换为正则表达式对象。基本语法是: ```javascript var regex = new RegExp(pattern [, flags]); ``` 其中,`pattern`是一个字符串,表示正则表达式的模式,`flags`是一个可选的字符串,包含标志(如`g`、`i`、`m`等)。 例如,如果我们有一个字符串`"abc"`,我们想将它换为全局不区分大小写的正则表达式,可以这样做: ```javascript var str = "abc"; var regex = new RegExp(str, "gi"); ``` 但是,需要注意的是,如果字符串中包含特殊字符(如`.`、`*`、`+`等),这些字符在正则表达式中具有特殊含义,直接换可能会导致非预期的结果。因此,有时我们需要对字符串进行义,将特殊字符前面加上反斜杠`\`,使其成为字面量。 然而,用户提供的引用中并没有直接提到义的问题,但根据正则表达式的知识,这是一个重要的考虑点。 引用[1]中提到了使用正则表达式来测试字符串格式,这说明了正则表达式的应用,但没有直接涉及字符串正则表达式的方法。 引用[2]和[3]是关于字符串处理的其他方面(分割字符串和字符编码),与当前问题关系不大。 引用[4]和[5]是关于其他主题(解析Newick树格式和Vim的折叠功能),与当前问题无关。 因此,我们主要依靠JavaScript的标准特性来实现换。 此外,我们还可以使用字面量形式来创建正则表达式,但这要求我们在编写代码时就知道模式,而不是在运行时通过字符串构建。所以,当模式是动态的(来自字符串变量)时,必须使用`RegExp`构造函数。 总结步骤: 1. 确保字符串模式是有效的正则表达式模式(注意义特殊字符)。 2. 使用`new RegExp(stringPattern, flags)`来创建正则表达式对象。 如果用户提供的字符串中包含特殊字符,且这些字符需要作为普通字符匹配,那么我们需要对字符串进行义。JavaScript没有内置的义函数,但我们可以自己编写一个函数来义正则表达式的特殊字符。 例如,义函数可以这样写: ```javascript function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // 义所有特殊字符 } ``` 然后,我们可以这样使用: ```javascript var str = "a.b.c"; // 字符串中包含特殊字符'.' var escapedStr = escapeRegExp(str); var regex = new RegExp(escapedStr, "g"); ``` 这样,正则表达式就会匹配字符串"a.b.c",而不是匹配"a"后跟任何字符再跟"b"再跟任何字符再跟"c"。 因此,在将字符串换为正则表达式时,我们需要根据需求决定是否进行义。如果字符串是作为正则表达式模式编写的(即字符串本身已经是一个合法的正则表达式字符串),那么直接使用`RegExp`构造函数即可。如果字符串是普通的文本,需要作为字面字符串进行匹配,那么就需要先义。 现在,我们可以按照用户的要求,用中文清晰地回答这个问题,并提供示例代码。 同时,根据系统指令,我们需要生成相关问题。</think>### 如何将 JavaScript 字符串换为正则表达式 在 JavaScript 中,将字符串换为正则表达式有两种主要方法: #### 1. 使用 `RegExp` 构造函数 这是最灵活的方法,支持动态创建正则表达式: ```javascript const patternStr = "\\d{3}-\\d{2}"; // 字符串格式的正则模式 const flags = "gi"; // 可选标志:g(全局), i(忽略大小写) // 创建正则对象 const regex = new RegExp(patternStr, flags); // 使用示例 "123-45 AB-67".match(regex); // 返回 ["123-45", "AB-67"] ``` **注意**: - 反斜杠 `\` 需要双重义(`\\d` 而不是 `\d`) - 支持动态拼接正则模式(如 `new RegExp("^" + userInput + "$")`) #### 2. 使用字面量语法(仅静态模式) 当正则模式是固定字符串时: ```javascript const regex = /\d{3}-\d{2}/gi; // 直接定义正则表达式 ``` #### 特殊字符处理 当字符串包含正则元字符(如 `. * + ?` 等)时,需先义: ```javascript function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // 义所有特殊字符 } const userInput = "file.txt"; const safeRegex = new RegExp(escapeRegExp(userInput), "i"); "FILE.TXT".match(safeRegex); // 返回 ["FILE.TXT"] ``` #### 验证正则有效性 使用 `try/catch` 避免无效正则导致的错误: ```javascript function safeRegExp(str, flags = "") { try { return new RegExp(str, flags); } catch { return /(?:)/; // 返回空正则作为兜底 } } ``` ### 应用场景 1. **动态模式匹配**:根据用户输入创建搜索条件 2. **文本高亮**:在富文本编辑器中动态生成高亮规则 3. **表单验证**:从配置文件中加载验证规则 > 提示:在换前建议先用 `typeof` 验证输入类型,避免非字符串输入导致意外错误[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值