Javascript Engine

0

Siemanko mam taki problem. Muszę napisać prosty kalkulator który sczytuje String typu "1/2" z konsoli od użytkownika, ale nie mogę używać żadnych ifów ,pętli itp w klasach javy. Więc wyjsciem jest napisanie skryptu i odpalenie go w javie. Problem w tym że nigdy nie widziałem java skryptu na oczy i szukam pomocy. Mogłby ktoś podać jakiś przykład takiego skryptu ktory operuje na argumentach z konsoli i podpowiedzieć gdzie ten plik umieścic? Umiesciłem jak na razie ten skrypt w folderze proejktu i dałem mu nazwę "JavaScript".

Napisałem do tej pory coś takiego:
Klasa Calc

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;


public class Calc {
    public String doCalc(String arg) {
        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("JavaScript");
        try {
            return engine.eval(arg).toString();
        } catch (ScriptException e) {
            return "Invalid command to calc";
        }
    }
}

Klasa Main

public class Main {

  public static void main(String[] args) {

  Calc c = new Calc();
  String wynik = c.doCalc(args[0]);
  System.out.println(wynik);
  }

}
0

Chwila, od początku
Jak dokładnie wygląda zadanie?

Teraz zrozumiałem to tak że masz za zadanie napisać kalkulator obliczający wyrażenia (zapewne RPN), ale nie możesz pisać warunków typu:

if (wyrazenie.Equals("1/2")) print("0.5");

więc wpadłeś na pomysł żeby włączyć do aplikacji cały silnik innego języka i do niego przesłać to wyrażenie? :|

Równie dobrze mógłbyś włączyć gotową bibliotekę "kalkulator" i do niej przesłać wyrażenie i odebrać wynik

0

Powiem tak, zadanie wyglada następujaco:

Napisać prosty kalkulator dla liczb typu BigDecimal.
Obliczenia mają być podawane jako argumenty wiersza poleceń w postaci:

liczba1 op liczba2

gdzie op jeden ze znaków +,- (minus), * (mnożenie), / (dzielenie), a pomiędzy liczba1, op i liczba2 występuje jeden lub więcej białych znaków.

Obliczenia zrealizować w klasie Calc jako metodę String doCalc(String cmd), zwracająca napisową reprezentację wyniku (uzyskanej liczby) lub napis "Invalid command to calc", jeśli wystąpią jakiekolwiek błędy.

Następująca klasa Main::

public class Main {

public static void main(String[] args) {
Calc c = new Calc();
String wynik = c.doCalc(args[0]);
System.out.println(wynik);
}

}
po uruchomieniu winna wyprowadzić na konsolę wynik obliczenia (np. jesli podano jako argument wiersza poleceń
"1 / 2" , to wynikiem powinine być napis 0.5.

Jeśli liczba wynikowa nie ma dokładnej reprezentacji (jak np. wynik dzielenia 1/3), to wynik powinien być pokazany z dokładnością co najmniej 7 miejsc dziesiętnych.

Uwaga 1: klasy Main nie wolno modyfikować i musi ona prawidłowo działać.

Uwaga 2: w zadnej z klas programu nie wolno używać instrukcji if, ani switch, ani operatora warunkowego, ani instrukcji for, ani isntrukcji while.

Wykłady poprzedzające to zadanie dotyczyły skryptów ,więc tego pewnie wymaga wykładowca :)

1

Kalkulator przeżywający orgazm to coś nowego, Twój program ma sczytywać dane z konsoli. A jeśli chodzi o pytanie, to:

Scanner sc = new Scanner(System.in);
while(true){
    System.out.print("Wpisz wyrażenie (exit by zakonczyc program): ");
    String expression = sc.nextLine();
    if(expression.equalsIgnoreCase("exit"){
        break;
    }
    try{
       System.out.println(expression+" = "+engine.eval(expression));
    }
    catch
    ...
}
0

Przedstawiłeś dwie zupełnie różne wersje zadania. Mój poprzedni post dotyczy pierwszej wersji zadania.
.

1
error91 napisał(a):

Uwaga 2: w zadnej z klas programu nie wolno używać instrukcji if, ani switch, ani operatora warunkowego, ani instrukcji for, ani isntrukcji while.

Wykłady poprzedzające to zadanie dotyczyły skryptów ,więc tego pewnie wymaga wykładowca :)</quote>

zapewniam że nie, chociaż po zobaczeniu takiej wersji na pewno by się uśmiechnął i zaliczył ;) zwłaszcza jeżeli mówił o tym na poprzednich zajęciach

Bardzo dziwne masz restrykcje, ale ja bym użył tu wyrażeń regularnych do wydzielenia liczb i operacji i użył tabeli do mapowania operatora na operację
Całość zamknąć w blok try - catch w którym będzie wypisywana informacja o błędzie i tyle - wymogi spełnione

0

Dzięki za poprawienie ortografii ,jednak napisałem nawet w pierwszej wersji ze nie mogę używać ifów i pętli

0

@Wieczny Knur, jestem cienki z wyrażeń regularnych. Jak (przy podanych ograniczeniach) odróżnić legalny argument wywołania "1 + 2" od nielegalnych 1+2 lub "1+2"?

0

Wiem że zadanie dziwne ,ale mam się dzieki niemu nauczyć właśnie korzystać z JSE. Takie jest raczej założenie ,może zadanie bez sensu ale sama umiejętność jest cenna. Na stackoverflow nawet ktoś podał taki przykład:
http://stackoverflow.com/questions/3422673/evaluating-a-math-expression-given-in-string-form

0

Dziwne, ale ciekawe. Z ciekawości zrobiłem, największy kłopot miałem z odróżnieniem legalnych argumentów typu "1 + 2","1 + 67" od nielegalnych "1+2", 1+2.

0

Dobra panowie już wiem. Przepisałem ten kod dosyć bezmyślnie nie zagllebiajac się w cały silnik. To co wysłałem już działa wystarczy uruchomić program z argumentami wywołania. W eclipse to Run Configuration -> Arguments. Program przesyła do silnika argumenty ktore sa "evaluowane" metodą eval do java scriptu a nastepnie zwracane do javy i zamieniane na string toStringiem().

0

Muszę Cię zmartwić, program nie spełnia warunków.

java Main 1+2 => 3 (a powinno być : Invalid command to calc)
java Main "1111111111111111111 + 2" => 1111111111111111168
java Main 1 + 2 => 1 (powinno być: Invalid command to calc)
0

Obliczenia mają być podawane jako argumenty wiersza poleceń w postaci:

liczba1 op liczba2

0

a pomiędzy liczba1, op i liczba2 występuje jeden lub więcej białych znaków
a w wyrażeniu 1+2 nie ma żadnego białego znaku.

0

w przykładzie jest napisane

po uruchomieniu winna wyprowadzić na konsolę wynik obliczenia (np. jesli podano jako argument wiersza poleceń
"1 / 2" , to wynikiem powinine być napis 0.5.

Poza tym liczby muszą być wpisane w cudzysłów ponieważ bez niego funkcja main

public class Main {

  public static void main(String[] args) {

  Calc c = new Calc();
  String wynik = c.doCalc(args[0]);
  System.out.println(wynik);
  }

} 

sczyta pojedynczą liczbę a jej zmieniac nie mogę, więc wyjscia innego nie widze.

0

Wiem, że trzeba argument wpisać w cudzysłów, ale argument "1/2" powinien zgodnie z wymaganiami skończyć się komunikatem o błędzie, a nie wynikiem 0.5.
Napisałem wcześniej, że zrobiłem zadanie. Korzystając z pomysłu @Wiecznego Knura napisałem program, który spełnia wszystkie wymagania.

0

a możesz powiedzieć jak to zrobileś bez użycia zadnych warunkow i pętli? bo mnie to ciekawi

1

A to nie chodzi o cos takiego:

interface Operation { int execute(int a, int b); }
class PlusOperation implements Operation { public int execute(int a, int b) { return a + b; } }
class TimesOperation implements Operation { public int execute(int a, int b) { return a * b; } }

Map<String, Operation> ops = new HashMap<>();
ops.put("+", new PlusOperation());
ops.put("*", new TimesOperation());

...

public String doCalc(String line) {
    try {
        String[] s = line.split("\\s+");
        int a = Integer.parseInt(s[0]);
        int b = Integer.parseInt(s[2]);
        Operation op = ops.get(s[1]);
        return "" + op.execute(a, b);
    } catch (Exception exc) {
        return "invalid command to calc";
    }
}

Kod oczywiscie uproszczony, ze skrotami myslowymi, nie parsuje poprawnie wszystkiego itp., ale chodzi o zasade. Nie ma ifow i calej zakazanej reszty.

1

Ja mam trochę bardziej skomplikowany kod, bo uwzględniam, że liczby maja być typu BigDecimal.

class Calc
{
    private HashMap<String,Method> methods = new HashMap<String,Method>();
    private MathContext mc = new MathContext(7);
    //------------------------
    public Calc()
    {
        try
        {
            Class klasa = Class.forName("java.math.BigDecimal");
            Method method = klasa.getMethod("add",BigDecimal.class);
            methods.put("+",method);
            method = klasa.getMethod("subtract",BigDecimal.class);
            methods.put("-",method);
            method = klasa.getMethod("multiply",BigDecimal.class);
            methods.put("*",method);
            method = klasa.getMethod("divide",BigDecimal.class,MathContext.class);
            methods.put("/",method);              
        }
        catch(ClassNotFoundException | NoSuchMethodException e)
        {

        }
    }
    //------------------------
    public String doCalc(String arg)
    {
        String[] items = arg.split("\\s+");
        BigDecimal arg1 = null;
        BigDecimal arg2 = null;
        Method method = null;
        BigDecimal result = null;
        try
        {
            arg1 = new BigDecimal(items[0]);
            arg2 = new BigDecimal(items[2]);
            method = methods.get(items[1]);
            result = (BigDecimal)method.invoke(arg1,arg2);
            return result.toString();
        }
        catch(IllegalArgumentException e)
        {
            try
            {
                result = (BigDecimal)method.invoke(arg1,arg2,mc);
                return result.toString();
            }
            catch(Exception e2)
            {
                return "Invalid command to calc";                
            }
        }
        catch (Exception e)
        {
            return "Invalid command to calc";
        }
    }
0

Dzięki ,nie znałem jako takiej klasy method poczytam o niej.

0

Tak tak, napisalem przeciez ze moj jest kiepski, ma pelno skrotow myslowych itp. Zasade jest jednak ta sama, command pattern.
Nie rozumiem tylko dlaczego robisz napierw string.replace a pozniej zplit z +, ten replace jest zbedny, i sprawia ze masz 2 operacje z regexami.
Po co masz to zagniezdzene w handlerze IllegalArgumentException? Kiedy to bedzie wykonane?

0
  1. Już poprawiłem początkowo miałem tylko
items = arg.split("\\s");

. Taki kod działał źle przy kilku białych znakach, zamiast zmienić regexa w metodzie split dopisałem nadmiarowe replace.
2. IllegalArgumentException pojawi się np. przy 1 / 3, ogólniej pojawi się zawsze, gdy wynik dzielenia ma nieskończenie wiele cyfr.

0

A ok, teraz widze - divide wymaga MathContext, a on nie jest uzywany, dopiero jak bedzie ten wyjatek jest przekazywany jako parametr.
Nie obraz, sie, ale ten kod jest strasznie brzydki i nieelegancki. I uzywa refleksji, yuck. Zakladam ze tak jak moj, to tylko na potrzeby prezentacji idei.

0

Zaintrygowało mnie to zadanie z dziwacznymi wymaganiami, więc napisałem ten kod (bez pretensji do elegancji). Jak wyobrażasz sobie elegancki kod, który spełnia wszystkie wymagania zadania?

0

Przede wszystim oczy mnie bola od uzycia refleksji zeby wolac metody danej klasy, wole dedykowany interfejs Command co jest moim zdaniem elastyczniejsze (co zrobisz jak nie ma danej operacji w klasie ktorej metody refleksyjnie pobierasz?). Proteza typu wolanie metody na pałę z takimi i takimi argumentami, a jak sie nie uda to moze z jeszcze jednym? To w sumie tyle. Mozliwe nawet ze twoj kod jest jedynym poprawnym ktory spelnia wymagania, nie zaglebialem sie, ale w moim mniemaniu wyglada dosc... srednio, wiem ze umiesz lepiej ;d

0

trafiłem na ten wątek, bo mam bardzo podobne zadanie do zrobienia...
generalnie wszystko działa mi dobrze, ale mam spory problem z podawaniem obliczeń jako argumentów wiersza poleceń, a w zasadzie z odróżnieniem argumentów prawidłowych od nieprawidłowych.
przykładowo polecenia:
java Main "100 / 4"
java Main "100 / 4
java Main "100 / 4 / 3
zwracają dokładnie taki sam wynik: 25

drugi problem to jak w przypadku działania 100 / 3 pokazać siedem miejsc dziesiętnych? opisywane rozwiązanie pokazuje łącznie 7 cyfr, czyli tylko 5 po przecinku...
Jarek

0

Więc wyjsciem jest napisanie skryptu i odpalenie go w javie. Problem w tym że nigdy nie widziałem java skryptu na oczy i szukam pomocy. (...) Umiesciłem jak na razie ten skrypt w folderze proejktu i dałem mu nazwę "JavaScript".

Seems legit. To trochę jakby jakiś Janusz biznesu założył małą firmę informatyczną i powiedział "moja firma jest mała, więc pierwszy człon będzie Micro, i będzie wytwarzała software więc drugi człon będzie Soft. I tym sposobem Janusz biznesu spod lubelskiej wsi nazywa swoją firmę Microsoft xD

Problem tylko taki, że o ile zarówno Microsoft jak i Javascript to idiotyczne nazwy, to jednak znaczą już od wielu lat coś konkretnego i nazywanie czegoś nowego w ten sposób teraz to głupi pomysł. Równie dobrze producent kibli mógłby nazwać swoje przenośne latryny Osram, bo gdzieś przeczytał tę nazwę i mu się tak skojarzyło XD

Ale anyway, to i tak temat sprzed roku ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1