26.10.2014, 19:50
|
Новичок на форуме
|
|
Регистрация: 26.10.2014
Сообщений: 7
|
|
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, затем все остальное по очереди. И обе части с возведением в степень ловятся, а вот в первом случае, по идее, чем оно отличается? Сначала ловится одно возведение в степень, затем должно парсить строку с промежуточным результатом, найти там еще одну возможность замены и сматчить. Но не делает этого. Почему?
|
|
26.10.2014, 20:32
|
Профессор
|
|
Регистрация: 23.10.2010
Сообщений: 2,718
|
|
После замены 2^2 больше нет 2^2, есть только ^2. Не факт что я ответил правильно, и это не важно. Не совсем понял что вы делаете, но если вычисляете выражение по кускам, то делается не так. Просто найдите токенизатор для калькуляторов и не надо свой писать.
|
|
26.10.2014, 20:38
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,105
|
|
Scampada,
пока в строке есть синусы -- они вычисляются - не match нужен а test строки и перезапись первого попавшегося синуса.
потом так-же косинусы
потом находятся первые любые скобки - если они есть - и в них вычисяется пока есть ^ и ! потом * / - + тоже пока есть - вместо скобок получили число -- ищем следующие скобки пока не закончатся -- скобок нет -- прогоняем результрующую строку по этому же алгоритму
^ ! */-+
|
|
26.10.2014, 20:38
|
Профессор
|
|
Регистрация: 23.10.2010
Сообщений: 2,718
|
|
Кстати, а вы не пробовали дописать к експрессион 'var result='+ и сделать над всей строкой eval?
|
|
26.10.2014, 20:53
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,105
|
|
Сообщение от kostyanet
|
Кстати, а вы не пробовали дописать к експрессион 'var result='+ и сделать над всей строкой eval?
|
Цитата:
|
Разбор строки осуществляется с помощью регулярных выражений
|
|
|
26.10.2014, 20:54
|
Новичок на форуме
|
|
Регистрация: 26.10.2014
Сообщений: 7
|
|
Сообщение от kostyanet
|
После замены 2^2 больше нет 2^2, есть только ^2. Не факт что я ответил правильно, и это не важно. Не совсем понял что вы делаете, но если вычисляете выражение по кускам, то делается не так. Просто найдите токенизатор для калькуляторов и не надо свой писать.
|
Нет. Алерт четко показывает, что есть: 4.00000000^2. Просто это выражение дальше не парсится, а отправляется на выход функции, а дальше от строки отрезается только четверка и идет на вывод.
|
|
26.10.2014, 20:55
|
Новичок на форуме
|
|
Регистрация: 26.10.2014
Сообщений: 7
|
|
Сообщение от kostyanet
|
Кстати, а вы не пробовали дописать к експрессион 'var result='+ и сделать над всей строкой eval?
|
Ну, как бы да: в чем тогда будет заключаться моя роль? Этак можно вообще ничего не писать и мозги не парить.
|
|
26.10.2014, 20:57
|
Новичок на форуме
|
|
Регистрация: 26.10.2014
Сообщений: 7
|
|
Сообщение от рони
|
Scampada,
пока в строке есть синусы -- они вычисляются - не match нужен а test строки и перезапись первого попавшегося синуса.
потом так-же косинусы
потом находятся первые любые скобки - если они есть - и в них вычисяется пока есть ^ и ! потом * / - + тоже пока есть - вместо скобок получили число -- ищем следующие скобки пока не закончатся -- скобок нет -- прогоняем результрующую строку по этому же алгоритму
^ ! */-+
|
Немного не понял про match, вернее про то, что он не нужен. Его и нет там вроде. replace как раз вроде и перезаписывает первое попавшееся совпадение и проверяет новую строку на дальнейшие совпадения.
Я вообще-то спрашивал про механизм действия str.replace, по какому принципу она делает глобальную замену...
|
|
26.10.2014, 21:24
|
Профессор
|
|
Регистрация: 23.10.2010
Сообщений: 2,718
|
|
Сообщение от Scampada
|
в чем тогда будет заключаться моя роль?
|
Ваша роль заключается в том чтобы мозги парить?
|
|
26.10.2014, 21:34
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,105
|
|
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')])
|
|
|
|