[Resolvido] Validar fórmula matemática que está como String

Boa tarde galera, tudo certo ? Bem, na minha aplicação tenho um campo em que o professor digita uma fórmula. Esta, vai servir para que ele avalie seus alunos. Nessa fórmula, o professor só podera digitar as letras np e números de 1 a 9 . Também, vai ser necessário verificar os parênteses, etc…
Abaixo, exemplo de fórmula:

((np1*0.25)+(np2*0.25)+(np3*0.25)+(np4*0.25))

Por exemplo, se o professor digitasse (np1 + ns2)/2, deveria informar um erro na fórmula…Se alguém puder ajudar, agradeço mto…Vlww

Você quer algo que te diga se a expressão é válida ou não? É isso?

Boa tarde Rodrigo, tdo certo? Não, na vdd estou tentando fazer o seguinte: Deixar o professor somente digitar np… Por exemplo:

(np1 + np2 +n np3 + np4 )/4

Se ele tentar colocar:

(ns1 + ns2 +n np3 + np4 )/4

Viria uma mensagem na tela por exemplo: verifique a fórmula… Além disso, também quero fazer ( depois que eu conseguir isso) verificar tipo, parênteses e tal, pra ver se estão sendo utilizandos no lugar correto…Não sei se fui claro… Mas conseguiu entender o início?? Tipo, ele só vai poder digitar as LETRAS NP… tendeu?? Daí vou ter que fazer a verificação quando ele salva, dentro do meu bean:

public void salva() { if (crudObj.getRecuperacao().equals("N")) { crudObj.setNotaRecuperacao(null); } if (!crudObj.getFormulaAvaliacao().isEmpty()) { //aki viria a verificação... } super.salva();
Se puder ajudar, agradeço mto… Vlw

Estou pesquisando aki sobre o uso de expressões regulares…Não sei se é a melhor forma de fazer as verificações que preciso…Alguém poderia ajudar?? Se alguém puder ajudar, agradeço mto…Vlw

Você pode usar uma expressão regular sim, o ideal é você definir o que pode aparecer na sua expressão. por exemplo:

1 - Números
2 - Parênteses
3 - Operadores matemáticos (+, -, *, /)
4 - np seguido de algum número

Qualquer coisa fora disso não seria válida. Então a regex teria que verificar todos os caracteres vendo se eles caem nesses critérios. Algo assim:private static boolean matches(String expr){ Pattern p = Pattern.compile("(\\d*|[+*/().-]|np\\d+|\\s+)*"); Matcher m = p.matcher(expr); return m.matches(); }

Já que você terá sempre 4 notas, uma ideia simples é fazer um javascript com a fórmula no programa em java, atribuir a nota zero para as variáveis np1 a np4 e pegar o output da execução da fórmula. Você terá um belo erro se a fórmula estiver sintaticamente incorreta e é só tratar esse caso.

Um exemplo você pode ver no próprio tópico que você abriu semana passada na mensagem do mauricioadl:

http://www.guj.com.br/java/304513-resolvido-interpretar-formula-matematica-que-esta-como-string

[quote=Rodrigo Sasaki]Você pode usar uma expressão regular sim, o ideal é você definir o que pode aparecer na sua expressão. por exemplo:

1 - Números
2 - Parênteses
3 - Operadores matemáticos (+, -, *, /)
4 - np seguido de algum número

Qualquer coisa fora disso não seria válida. Então a regex teria que verificar todos os caracteres vendo se eles caem nesses critérios. Algo assim:private static boolean matches(String expr){ Pattern p = Pattern.compile("(\\d*|[+*/().-]|np\\d+|\\s+)*"); Matcher m = p.matcher(expr); return m.matches(); }[/quote]
Bom dia Rodrigo…Isso aí caa, excelente idéia…Os quatro itens que você citou posso utilizar sim!! Mas, como eu poderia fazer pra testar se foi digitado algo fora do contexto que o profesor pode digitar no caso, algo fora dos 4 itens?? Vlw por estar ajudando cara!!

[quote=Ricardo Fávero Júnior][quote=Rodrigo Sasaki]Você pode usar uma expressão regular sim, o ideal é você definir o que pode aparecer na sua expressão. por exemplo:

1 - Números
2 - Parênteses
3 - Operadores matemáticos (+, -, *, /)
4 - np seguido de algum número

Qualquer coisa fora disso não seria válida. Então a regex teria que verificar todos os caracteres vendo se eles caem nesses critérios. Algo assim:private static boolean matches(String expr){ Pattern p = Pattern.compile("(\\d*|[+*/().-]|np\\d+|\\s+)*"); Matcher m = p.matcher(expr); return m.matches(); }[/quote]
Bom dia Rodrigo…Isso aí caa, excelente idéia…Os quatro itens que você citou posso utilizar sim!! Mas, como eu poderia fazer pra testar se foi digitado algo fora do contexto que o profesor pode digitar no caso, algo fora dos 4 itens?? Vlw por estar ajudando cara!![/quote]
No caso, como vou testar quando vou salvar, devo fazer dessa maneira? :

  private static boolean matches(String expr) {
        Pattern p = Pattern.compile("(\\d*|[+*/().-]|np\\d+|\\s+)*");
        Matcher m = p.matcher(expr);
        return m.matches();
    }

    @Override
    public void salva() {
        if (crudObj.getRecuperacao().equals("N")) {
            crudObj.setNotaRecuperacao(null);
        }
        if (!crudObj.getFormulaAvaliacao().isEmpty()) {
          matches(crudObj.getFormulaAvaliacao());
        }
        super.salva();
    }

Não, o matches retorna um boolean, você tem que decidir o que fazer dependendo do valor que ele retornar.

Blz… Vou testar aki e já posto o resultado…Vlww

Fiz da seguinte maneira:

    private boolean formulaAvaliacaoVerdadeira() {
        Pattern p = Pattern.compile("(\\d*|[+*/().-]|np\\d+|\\s+)*");
        Matcher m = p.matcher(crudObj.getFormulaAvaliacao());
        return m.matches();
    }

    @Override
    public void salva() {
        if (!crudObj.getFormulaAvaliacao().isEmpty()) {
            if (formulaAvaliacaoVerdadeira()) {
                if (crudObj.getRecuperacao().equals("N")) {
                    crudObj.setNotaRecuperacao(null);
                }
                super.salva();
            } else {
                JsfUtil.warn("Fórmula de Avaliação Inválida. Verifique.");
            }
        }
    }

Funcionou perfeitamente Rodrigo. Vc como sempre, vem com boas ideias quando responde os tópicos aki ehehe. Cara, mas estou afim de ir mais além… Teria como verificar mais " a fundo " a expressão ? No caso, por exemplo do seguinte:

((np1*0.25)+(np2*0.25)+(np3*0.25)+(np4*0.25)))

Se a expressão tiver um parênteses a mais… Dá pra dar uma ajuda aí?? Vlw…

Bom, aí você vai ter que ser criativo :slight_smile:

Dizem que o custo de realizar o cálculo é o mesmo, ou pelo menos é muito próximo, do custo de validar a expressão. Então eu nem faria isso, tentaria avaliar a expressão, se alguma exceção fosse lançada eu repassaria.

mas se quiser fazer isso mesmo pode simplesmente contar os parênteses. Pegue uma variável numérica, para cada parênteses aberto incremente 1, para cada fechado decremente 1. No final essa variável tem que ter valor 0

[quote=Rodrigo Sasaki]Bom, aí você vai ter que ser criativo :slight_smile:

Dizem que o custo de realizar o cálculo é o mesmo, ou pelo menos é muito próximo, do custo de validar a expressão. Então eu nem faria isso, tentaria avaliar a expressão, se alguma exceção fosse lançada eu repassaria.

mas se quiser fazer isso mesmo pode simplesmente contar os parênteses. Pegue uma variável numérica, para cada parênteses aberto incremente 1, para cada fechado decremente 1. No final essa variável tem que ter valor 0[/quote]
Bhá cara, boa idéia…Estou vendo como vc fez e queria sabeer o seguinte: se eu tiver a seguinte fórmula:

(nt+ne)/2

Podendo também ser:

((nt*0.25)+ne*0.25))/2

Como ficaria a expressão? Ou melhor, como coloco que pode ter somente nt e ne e não pode ter números depois deles ( diferente da outra que tenho por exemplo np1, np2). To tentando ver naquela que me passou mas nao to conseguindo descobrir…

Expressões regulares tem que ser pensadas passo a passo, vamos pegar o seu caso.

O primeiro caractere tem que ser um n, então nossa regex representa isso:

regex -> “n”

O segundo caractere pode ser t ou e

regex -> “n[te]”

E assim você vai evoluindo

[quote=Rodrigo Sasaki]Expressões regulares tem que ser pensadas passo a passo, vamos pegar o seu caso.

O primeiro caractere tem que ser um n, então nossa regex representa isso:

regex -> “n”

O segundo caractere pode ser t ou e

regex -> “n[te]”

E assim você vai evoluindo[/quote]
Hm, to entendendo…No meu caso então, ficaria quase assim?

 private boolean formulaAvalMediaFinalVerdadeira() {
        Pattern p = Pattern.compile("(\\d*|[+*/().-]|n[te]\\d+|\\s+)*");
        Matcher m = p.matcher(crudObj.getFormulAvalMediaFinal());
        return m.matches();
    }

Uma dúvida: essa parte |n[te]\d+|\s+ diz repeito as variáveis que pode ter na expressão e que tem números, é isso ? Se não qeuro que tenha números, como ficaria?? To lendo aki oque encontrei: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html

Se não quer que tenha números não pode ter o \d+ na frente :slight_smile:

Rodrigo, fiz o seguinte entao:

    private boolean formulaAvalMediaFinalVerdadeira() {
        Pattern p = Pattern.compile("(\\d*|[+*/().-]|n[te]\\d+|\\s+)*");
        Matcher m = p.matcher(crudObj.getFormulAvalMediaFinal());
        return m.matches();
    }

Para a seguinte fórmula,por exemplo:

(nt + ne)/2

E tá retornando false, poderia dizer o pq??Vlw…

Por que você disse que o nt ou ne precisam ter um número na frente.

n[te]\d+

[quote=Rodrigo Sasaki]Por que você disse que o nt ou ne precisam ter um número na frente.

n[te]\d+[/quote]
Desculpe cara, desculpe msms, depois que postei fui ver a mesangem denovo… Mal aí…

[quote=Rodrigo Sasaki]Bom, aí você vai ter que ser criativo :slight_smile:

Dizem que o custo de realizar o cálculo é o mesmo, ou pelo menos é muito próximo, do custo de validar a expressão. Então eu nem faria isso, tentaria avaliar a expressão, se alguma exceção fosse lançada eu repassaria.

mas se quiser fazer isso mesmo pode simplesmente contar os parênteses. Pegue uma variável numérica, para cada parênteses aberto incremente 1, para cada fechado decremente 1. No final essa variável tem que ter valor 0[/quote]
Certa vez, na faculdade, acredito que foi no 3º Semestre do Curso (estou no 4º semestre) de Ciência da Computação, fiz o seguinte em C++ para verificar os parênteses…

#include <iostream>
#include <stack>
 
using namespace std;
 
    int main (){
 
        int N;
        string caracter;
        while (cin >> caracter){
            stack <int> pilha1, pilha_2; // declaracao da pilha (no caso inteiros numeros)
            for(int i=0; i < caracter.size(); i++){
                if(caracter[i] =='('){
                    pilha1.push(caracter[i]); // caracter[i]eh o q eu quero por na pilha
                }
                if(caracter[i] == ')'){  // verifica o caracter & ve se a pilha não esta vazia
                    pilha_2.push(caracter[i]);
                }
                if(caracter[i] == ')' && pilha1.size() != 0){  //  pilha.size() != 0 eh pra ver se ta vasia
                    pilha1.pop();
                    pilha_2.pop();
                }
        }
        if(pilha1.size() == 0 && pilha_2.size() == 0){
            cout << "correct" << endl;
        }else{
            cout << "incorrect" << endl;
        }
        }
 
return 0;
}

Estou tentando agora fazer isso em java…Não estou tendo mto sucesso… Não sei se devo usar um Stack tbm…Alguma idéia?? Estou tentando fazer da seguinte maneira: Devo ler a string ( minha fórmula) e contar quantas vezes aparece o caracter “(” e depois tbm ler e contar quantas vezes aparece o “)” . Se forem iguais a zero quando diminuo os dois, está correto, caso contrário falso…

    private boolean testeIncrementaDecrementa() {
        int incr = 0;
        int decr = 0;
        String caracter = "(";
        String caracter2 = ")";
        for (int i = 0; i < crudObj.getFormulaAvaliacao().length(); i++) {
            if (crudObj.getFormulaAvaliacao().contains(caracter)) {
                incr = incr + 1;
            }
            if (crudObj.getFormulaAvaliacao().contains(caracter2)) {
                decr = decr + 1;
            }
        }
        if (incr - decr != 0) {
            return false;
        } else {
            return true;
        }
    }

Poderia continuar ajudando?? Vlw cara, vlw mesmo por estar ajudando…