str.replace, не понимаю механизм глобальной замены
Привет, народ. Есть функция, которая парсит строку на предмет функций и заменяет их соответствующими значениями.
http://jsfiddle.net/johnthecreeper/ERSA2/116/ Здесь полный код. Вот сама функция: function specFuncs(expression){ var funcList = /(sin\(\d+\.?\d*\))|(cos\(\d+\.?\d*\))|(\d+\.?\d*\^\d+\.?\d*)|(\d+\.?\d*\!)/gi; expression = expression.replace(funcList, function(match,p1,p2,p3,p4,offset,string){ switch(match) { case p1: return Math.sin(parseFloat(match.replace(/[^\d+?\.\d*?]/gi,""))*(Math.PI/180)).toFixed(10).toString(); case p2: return Math.cos(parseFloat(match.replace(/[^\d+?\.\d*?]/gi,""))*(Math.PI/180)).toFixed(10).toString(); case p3: return Math.pow(match.split("^")[0],match.split("^")[1]).toFixed(10).toString(); case p4: var temp = 1; match = parseInt(match); while(match) temp *= match--; return temp.toFixed(10).toString(); } }); return expression; } На данный момент все работает, но я пытаюсь обработать такую строку: 2^2^2, после чего получаю результат 4. Добавляю в функцию алерты для выяснения сколько раз и для чего вызывается замена, и получается, что в первый раз функция замены ловит 2^2, а затем отдает на выход функции недорешенную строку 4.00000000^2. Сама по себе такая строка тоже парсится и решается, отдельно. При этом строка, например, вида 2^2 + 2! -3^1 парсится правильно, то есть сначала ловится 2^2, затем все остальное по очереди. И обе части с возведением в степень ловятся, а вот в первом случае, по идее, чем оно отличается? Сначала ловится одно возведение в степень, затем должно парсить строку с промежуточным результатом, найти там еще одну возможность замены и сматчить. Но не делает этого. Почему? |
После замены 2^2 больше нет 2^2, есть только ^2. Не факт что я ответил правильно, и это не важно. Не совсем понял что вы делаете, но если вычисляете выражение по кускам, то делается не так. Просто найдите токенизатор для калькуляторов и не надо свой писать.
|
Scampada,
пока в строке есть синусы -- они вычисляются - не match нужен а test строки и перезапись первого попавшегося синуса. потом так-же косинусы потом находятся первые любые скобки - если они есть - и в них вычисяется пока есть ^ и ! потом * / - + тоже пока есть - вместо скобок получили число -- ищем следующие скобки пока не закончатся -- скобок нет -- прогоняем результрующую строку по этому же алгоритму ^ ! */-+ |
Кстати, а вы не пробовали дописать к експрессион 'var result='+ и сделать над всей строкой eval?
|
Цитата:
Цитата:
|
Цитата:
|
Цитата:
|
Цитата:
Я вообще-то спрашивал про механизм действия str.replace, по какому принципу она делает глобальную замену... |
Цитата:
|
Scampada,
примерно так без скобок и синусов function calc(str) { str = str.replace(/\s+/g, ''); var re = /(\d+(\.\d+)*)\!/; for (; re.test(str);) {str = str.replace(re, function (a, b) { var temp = 1; b = parseInt(b); while(b) temp *= b--; return temp.toFixed(10).toString(); } ) }; re = /(\d+\.?\d*)\^(\d+\.?\d*)/; for (; re.test(str);) {str = str.replace(re, function (a, b, c) { return Math.pow(b, c).toFixed(10).toString(); } ) }; re = /(-*\d+\.?\d*)\/(-*\d+\.?\d*)/; for (; re.test(str);) {str = str.replace(re, function (a, b, c) { return (b / c).toFixed(10).toString(); } ) }; re = /(-*\d+\.?\d*)\*(-*\d+\.?\d*)/; for (; re.test(str);) {str = str.replace(re, function (a, b, c) { return (b * c).toFixed(10).toString(); } ) }; re = /(-*\d+\.?\d*)\-(-*\d+\.?\d*)/; for (; re.test(str);) {str = str.replace(re, function (a, b, c) { return (b - c).toFixed(10).toString(); } ) }; re = /(-*\d+\.?\d*)\+(-*\d+\.?\d*)/; for (; re.test(str);) {str = str.replace(re, function (a, b, c) { return (+b + +c).toFixed(10).toString(); } ) }; return str } alert([calc('2^2^2'),calc('2^2 + 2! -3^1'),calc('-5 + -5')]) |
Часовой пояс GMT +3, время: 23:22. |