C++/interpretacja danych na wejsciu

0

Witam
mam do zrobiernia program działajacy na liczbach zespolonych i nie wiem jak rozwiazac taki problem
uzytkownik ma wpisac wyrazenie w postaci np :
(2+3i)+(4+6i)
a program musi to odpowiednio zinterpretowac i obliczyc, tylko nie wiem jak spowodowac zeby wyluskac z tego tylko potrzebne liczby. Bylbym bardzo wdzieczny za jakakolwiek podpowiedz:)

0

Ja bym to zrobił w dwóch fazach. Na początku jeżeli między liczbą a i nie ma innego tokenu (może być znak biały) to wstawiłbym " * ". W drugiej fazie po prostu bym to sparsował do ONP zmieniając 'i' na std::complex<double>(0,1).

0

Polecam Boost.Spirit, który służy właśnie do robienia tego typu prostych parserów w dość prosty sposób. Ponadto opiera się na samych nagłówkach Boosta, więc nie ma potrzeby linkowania do zewnętrznych bibliotek.

Oto jak zaimplementować parser dla typu complex<double> (kiedyś zrobiłem dla zabawy i nauki). Parsuje liczby zespolone w postaciach (Re, Im i), Re, Im i, Re+Im i na przykład:

(12,45)
1+3i
-i
0.5
-1e4-0.1i
(4-1.2e-3i)
2i

Obsługuje również stałe -- domyślnie tylko Pi i E, ale można łatwo zdefiniować własne w pliku complex_parser_impl.h za pomocą makra REGISTER_CONST.

complex_parser.h

#pragma once

#include <complex>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

namespace complex
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    namespace phoenix = boost::phoenix;

    template <typename Iterator>
    struct complex_parser : qi::grammar<Iterator, std::complex<double>(), ascii::space_type>
    {
        complex_parser();

        qi::rule<Iterator, std::complex<double>(), ascii::space_type> value;
        qi::rule<Iterator, std::complex<double>(), ascii::space_type> imag;
        qi::rule<Iterator, double(), ascii::space_type> number;
    };

    extern complex_parser<std::string::const_iterator> complex_;
}

complex_parser_impl.h

#pragma once

#include "complex_parser.h"

#define REGISTER_CONST(name, value) \
    | -lit('+') >> string(#name)[_val =  (value)] \
    |  lit('-') >> string(#name)[_val = -(value)] \
    /**/

namespace complex
{
    template <typename Iterator>
    complex_parser<Iterator>::complex_parser() : complex_parser::base_type(value)
    {
        using qi::double_;
        using qi::string;
        using qi::eps;
        using qi::_1;
        using qi::_val;
        using qi::lit;
        using phoenix::construct;

        number = 
            double_[_val = _1]
            REGISTER_CONST(Pi, 3.1415926535897932384626433832795029)
            REGISTER_CONST(E,  2.7182818284590452353602874713526624)
        ;
        
        imag = 
                ( -lit('+') >> lit('i')[_val = construct<std::complex<double> >(0.0,  1.0)] )
            |   (  lit('-') >> lit('i')[_val = construct<std::complex<double> >(0.0, -1.0)] )
            |   ( number[_val = construct<std::complex<double> >(0.0, _1)] >> 'i' )
        ;
        
        value = 
                ( '(' >> number[_val = construct<std::complex<double> >(_1, 0.0)] 
                      >> ',' 
                      >> number[_val += construct<std::complex<double> >(0.0, _1)]
                  > ')'
                )
            |   ( '(' >> value[_val = _1] > ')' )
            |   ( imag[_val = _1] )
            |   ( number[_val = construct<std::complex<double> >(_1, 0.0)] 
                >> -( 
                        ( '+' >> imag[_val += _1] )
                      | ( '-' >> imag[_val -= _1] ) 
                    ) 
                )
        ;
        
        value.name("value");
        number.name("number");
        imag.name("imaginary-part");

        using phoenix::val;;
        
        qi::on_error<qi::fail>
        (
            value
          , std::cerr
                << val("Error! Expecting ")
                << qi::_4 // what failed?
                << val(" here: \"")
                << construct<std::string>(qi::_3, qi::_2) // iterators to error-pos, end
                << val("\"")
                << std::endl
        );
    }
}

complex_parser.cpp

#include "complex_parser_def.h"

namespace complex
{
    typedef std::string::const_iterator iterator_type;
    template complex_parser<iterator_type>::complex_parser();
    complex_parser<std::string::const_iterator> complex_;
}

Przykład użycia

#include <iostream>
#include <string>
#include <complex>
#include <vector>
 
#include "complex_parser.h"
 
int main(int argc, char* argv[])
{
    std::string str;
    while (getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;
     
        std::vector<std::complex<double> > numbers;
        std::vector<char> operators;
     
        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
     
        using complex::complex_;
        using complex::qi::char_;
        using complex::qi::_1;
        using complex::phoenix::push_back;
        using complex::phoenix::ref;
     
        bool r = boost::spirit::qi::phrase_parse(
            iter, 
            end, 
            (
                complex_[push_back(ref(numbers), _1)]
              % char_("-+*/^")[push_back(ref(operators), _1)]
            ),
            boost::spirit::ascii::space
        );
     
        if (r && iter == end)
        {
            std::cout << "Formula entered:\n";
            size_t i = 0;
            while (i < operators.size())
            {
                std::cout << numbers[i] << ' ' << operators[i] << ' ';
                ++i;
            }
            std::cout << numbers[i] << '\n';
        }
        else
            std::cerr << "Parsing failed.\n";
    }
    return 0;
}

Ten kod pozwala na parsowanie liczb zespolonych oddzielonych pojedynczymi znakami +, -, *, /, ^. Kolejne liczby są dopisywane do wektora numbers, a kolejne znaki oddzielające do wektora operators.

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