Kalkulator używając arraya, ze stringiem jako input
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!

Kalkulator używając arraya, ze stringiem jako input

AutorWiadomość
Temat założony przez niniejszego użytkownika
Kalkulator używając arraya, ze stringiem jako input
» 2019-02-10 12:28:19
Siemanko, mam problem. Głowię się z tym już dłuższą chwilkę. Chcę napisać algorytm, który po wprowadzeniu jakiegoś działania matematycznego, składającego się jedynie ze znaków +, /, -, *, i nawiasów (, ), policzy mi wynik tego działania. Oczywiście może to być działanie wieloczłonowe, mam na myśli, że z użyciem kilku liczb, a nie jedynie jednego operatora i dwóch liczb - bo takie coś jest za proste. Na chwilę obecną stoję w miejscu, gdzie po zaczytaniu działania, przepisuje mi je do tablicy. Jedynie problem jest taki, że mój algorytm odpowiadający za łączenie sąsiednich cyfr w liczbę nie chce działać, zasymulujmy co mam na myśli:

tab = { 2, 0, 4, +, 5, 3, *, 2};

powiedzmy, że to jest nasze działanie matematyczne po przerzuceniu do tablicy i teraz chcę sprawić, aby wszystkie sąsiednie cyfry znajdowały się pod jednym indeksem, aby później było łatwiej je parsować do integera i liczyć, czyli:

tab = { 204, +, 53, *, 2};

ma ktoś jakiś pomysł? wkleję tu swój algorytm, który niestety działa tylko dla jednego indeksu, nie wiem czy może jest tu problem z pętlą czy z czym innym.

C/C++
for( int j = 0; j < expression.length(); j++ ) {
    if( exp_tab[ j ] != "/" || "+" || "-" || "*" || ")" || "(" ) {
        if( exp_tab[ j + 1 ] != "/" || "+" || "-" || "*" || ")" || "(" ) {
            exp_tab[ j ] += exp_tab[ j + 1 ];
            exp_tab[ j + 1 ] = "";
        }
    }
}

exp_tab[i] = tablica typu string, w której przechowuje zmienne po przerzuceniu ze stringa,

expression = zmienna typu string, input naszego działania. Użyłem tam expression.length() aby prościej było sprawdzić wielkość tablicy.

A tu jest cały kod mojego programu, na końcu jest pętla wypisująca wszystkie dane z tablicy, rozdzielając je spacją by sprawdzić, czy się połączyły.

C/C++
#include "pch.h"
#include <iostream>
#include <string>

int main()
{
    std::string expression = "", exp_var = "", exp_tab[ 64 ];
   
    std::cout << "expression: ";
    std::cin >> expression;
   
    for( int i = 0; i < expression.length(); i++ ) {
        exp_tab[ i ] = expression[ i ];
    }
   
    for( int j = 0; j < expression.length(); j++ ) {
        if( exp_tab[ j ] != "/" || "+" || "-" || "*" || ")" || "(" ) {
            if( exp_tab[ j + 1 ] != "/" || "+" || "-" || "*" || ")" || "(" ) {
                exp_tab[ j ] += exp_tab[ j + 1 ];
                exp_tab[ j + 1 ] = "";
            }
        }
    }
   
    for( int k = 0; k < expression.length(); k++ ) {
        std::cout << exp_tab[ k ] << " ";
    }
}
P-173929
» 2019-02-10 13:34:12
Tak się nie pisze złożonych warunków:
if( exp_tab[ j ] != "/" || "+" || "-" || "*" || ")" || "(" )

Raczej powinno być tak:
if( exp_tab[ j ] != "/" && exp_tab[ j ] != "+" && exp_tab[ j ] != "-" && exp_tab[ j ] != "*" && exp_tab[ j ] != ")" && exp_tab[ j ] != "(" )

co można krócej zapisać tak:
if( std::string( "+-*/()" ).find( exp_tab[ j ] ) == std::string::npos )


Tylko że to w ogóle nie jest dobre podejście.
P-173930
» 2019-02-12 08:40:29
co można krócej zapisać tak:
if( std::string( "+-*/()" ).find( exp_tab[ j ] ) == std::string::npos )


Czy jest jakiś szczególny powód aby zapisywać warunek tak jak powyżej, a nie np. tak?:

if( std::string( exp_tab[ j ] ).find_first_of( "+-*/()" ) == std::string::npos )


Jakie byłoby dobre podejście do tego zadania?
P-173933
» 2019-02-12 12:07:08
W tym wypadku find_first_of będzie nawet lepsze, bo nie trzeba tworzyć stringa, exp_tab[j] już jest stringiem
if( exp_tab[ j ].find_first_of( "+-*/()" ) == std::string::npos )


Jakie byłoby dobre podejście do tego zadania?
Nie wiem jakie jest dobre, ale lepiej moim zdaniem wykorzystać to co oferuje biblioteka standardowa:
C/C++
#include <iostream>
#include <cctype>
#include <sstream>
#include <vector>
#include <variant>

int main()
{
    std::stringstream input( "256 * 2 + 13/8 * (-123 + 9 * 7)" );
    std::vector < std::variant < char, int >> tokens;
    char ch;
    while( input >> ch )
    {
        if( ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' )
             tokens.push_back( ch );
        else if( std::isdigit( static_cast < unsigned char >( ch ) ) )
        {
            input.putback( ch );
            int x;
            input >> x;
            tokens.push_back( x );
        }
        else
             std::cout << "bad char '" << ch << "'\n";
       
    }
   
    for( const auto & t: tokens )
    std::visit([]( const auto & t ) { std::cout << t << '\n'; }, t );
}

A być może jeszcze lepiej zamiast zapisywać tokeny do wektora od razu parsować wyrażenie parserem rekursywnym (bo ten jest łatwy do zaprogramowania).
P-173938
» 2019-02-12 19:43:33
Dziękuję za przykład. Szacunek. Długa droga przede mną.
P-173941
« 1 »
 Strona 1 z 1