2011-01-24 26 views
5

Oto interesująca. Ktoś ma dobry REGEX za konwersję wszystkich (pierwszy)^(drugi) do Math.pow ((pierwszy), (drugi))?RegEx dla^b zamiast pow (a, b)

EDIT:

Najlepszym mam tak daleko jest

s = s.replace(/((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))\s*\^\s*((?:\d+\.?\d*)|\w+|\((?:(?:[^\(\)]*(?:\([^\(\)]*\)))*)\))/g, 'Math.pow($1, $2)') // replace expression^expression with Math.pow($1, $2) 

Odpowiedzi do tej pory nie są wystarczająco ogóle. Nie obejmują czegoś takiego jak (var1 + var2)^2 nie dotyczy (var1 * (var2 + var3))^2

Rozwiązanie będzie musiało pracować z nawiasami.

Możesz użyć strfriend.com, aby wizualizować wyrażenie regularne w trakcie jego tworzenia. Właśnie to robiłem.

+3

A najbliższy jest teraz ...? – Oswald

+4

Do czego powinien zostać przekonwertowany symbol "a * b^c'? 'a^b + c'? 'a^b^c'? –

+5

Nie można tego zrobić w zwykłym regex. Wymaga arbitralnej rekursji. Jeśli chcesz otrzymać odpowiedź, sugeruję, abyś podniósł nagrodę, jest to dość skomplikowany problem. – kelloti

Odpowiedz

11

ta nie może być wykonana z regex (przynajmniej nie bez wielu wysiłku). Trzeba wziąć pod uwagę różne warstwy nawiasów, które nie mogą być obsługiwane za pomocą prostego wyrażenia regularnego. Proponuję poszukać biblioteki zdolnej do analizowania wyrażeń matematycznych. Lub będziesz musiał ograniczyć możliwe wyrażenie do czegoś, z czym możesz sobie poradzić za pomocą prostego wyrażenia regularnego.

Istnieje możliwość zdefiniowania nazwanych i równoważących grup przechwytywania w wyrażeniu regularnym, które mogą być używane (odsyłacze wsteczne) w tym samym wyrażeniu regularnym. W tym celu należy zdefiniować pożądany podzbiór składni matematycznej i oba przechwycone parametry. Sugeruję, że nie powinieneś odkrywać koła na nowo i używać biblioteki JS.

http://snippets.dzone.com/posts/show/2207

+3

Mattias jest tutaj; jeśli masz język z zagnieżdżonymi konstrukcjami, takimi jak parens, to zwykły język po prostu go nie przerwie - w rzeczywistości jest tam w definicji "zwykłego języka". Lepiej zacząć pisać parser lub znaleźć jednego z wielu. –

2

Można użyć String.replace:

> s = "hello 2^3 pow!" 
> s.replace(/(\d+)\^(\d+)/, "Math.pow($1, $2)") 
"hello Math.pow(2, 3) pow!" 
1

Zakładając chcesz przekonwertować pliki źródłowe czy coś takiego, wziąć skrypt perla pracuje nad swoimi plikami źródłowymi i używać Math::Expression::Evaluator::Parser. Z podsumowania:

use Math::Expression::Evaluator::Parser; 

my $exp = '2 + a * 4'; 
my $ast = Math::Expression::Evaluator::Parser::parse($exp, {}); 
# $ast is now something like this: 
# $ast = ['+', 
#   2, 
#   ['*', 
#   ['$', 'a'], 
#   4 
#   ] 
#  ]; 

Wygląda na to, że może z łatwością obsługiwać potęgowanie. Więc AST w Twoim przypadku będzie coś jak:

# $ast = ['^', 
#   base, 
#   exp 
#  ]; 

Można by zbudować pożądany wyraz „Math.pow (podstawa, exp)” przez (rekurencyjnie) zmontować ciąg od „bazy” i „exp” poddrzew.

Jeśli chcesz zaimplementować kalkulator w JavaScript, potrzebujesz oczywiście JavaScript-Parser lub możesz polegać na zapleczu serwerowym zaimplementowanym za pomocą Math :: Expression :: Evaluator.

+0

To lub odpowiedź, która omawia wdrożenie podobnych funkcji w JS, jest poprawną odpowiedzią. – Incognito

1

Złe wieści: wyrażenia regularne nie będą go wycinać (jak wskazuje wiele odpowiedzi), musisz napisać do tego parser.

Dobra wiadomość: stosunkowo łatwo można to zrobić w niemal dowolnym języku, pisząc parser rekursywny. Powinieneś oczywiście ponownie użyć istniejącego kodu tak bardzo, jak to możliwe, ale sam kodowanie rekurencyjnego parsera zejścia (i zobaczenie, w jaki sposób kodujesz zasady pierwszeństwa), może być polecane wyłącznie dla oświecającego doświadczenia.

Odbierz dowolną książkę na temat kompilacji i przeczytaj kilka pierwszych rozdziałów dotyczących analizowania. Pozwól mi polecić this freely available book Niklausa Wirtha, odszukaj 4.1 "Metoda rekurencyjnego zejścia".

0
var caretReplace = function(_s) { 
    if (_s.indexOf("^") > -1) { 
     var tab = []; 
     var powfunc="Math.pow"; 
     var joker = "___joker___"; 
     while (_s.indexOf("(") > -1) { 
      _s = _s.replace(/(\([^\(\)]*\))/g, function(m, t) { 
       tab.push(t); 
       return (joker + (tab.length - 1)); 
      }); 
     } 

     tab.push(_s); 
     _s = joker + (tab.length - 1); 
     while (_s.indexOf(joker) > -1) { 
      _s = _s.replace(new RegExp(joker + "(\\d+)", "g"), function(m, d) { 
       return tab[d].replace(/(\w*)\^(\w*)/g, powfunc+"($1,$2)"); 
      }); 
     } 
    } 
    return _s; 
}; 
  1. console.log(caretReplace("(3*(f(x^2)-2)^2+1^5-g(2^3+1)^5)^(9-2^3)")); daje Math.pow((3*Math.pow((f(Math.pow(x,2))-2),2)+Math.pow(1,5)-Math.pow(g(Math.pow(2,3)+1),5)),(9-Math.pow(2,3))).

  2. Wyrażenie matematyczne musi być poprawne, z dobrze zrównoważonymi nawiasami otwartymi i zamkniętymi.

  3. Możesz zastąpić Math.pow dowolną nazwą funkcji.

  4. Zrobiłem to, zastępując wszystkie nawiasy, od najbardziej wewnętrznych do najbardziej zewnętrznych, tekstami nie matematycznymi (___joker___0, ___joker___1, itp.). Na koniec analizuję wszystkie te łańcuchy w sposób hierarchiczny, aby zastąpić opiekunów wyrażeniami bez nawiasów.

Powiązane problemy