Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Zamiana liczby słownej na ciąg cyfr.

Ostatnio zmodyfikowano 2013-04-01 23:47
Autor Wiadomość
Rasoir
Temat założony przez niniejszego użytkownika
Zamiana liczby słownej na ciąg cyfr.
» 2013-03-30 18:58:14
Cześć!
Mam do napisania program który będzie zamieniał liczby na słowa i słowa na liczby ( tzn jak napiszę trzy do wyświetli mi 3), a potem dodawanie tych liczb (czyli napiszę trzy plus trzy wyświetli mi 6).
Pierwszą część programu czyli zamianę liczby na słowa zrobiłem zgodnie z algorytmem znalezionym w internecie, mam problem z drugą częścią.
Nie bardzo wiem jak się do tego zabrać, mój zamysł był taki żeby wpisać liczbę słownie w konsoli (jako zmienną typu string), podzielić stringa na wyrazy (tokeny), przepisać tokeny do tablicy. Potem odczytać tablicę od tyłu i sumować kolejno wartości na które wskazywał by dany string (czyli np dwadzieścia dwa to by było 2 + 20).
Czytałem już o różnych bibliotekach i funkcjach (np. strtok, atoi), ale nadal nie wiem jak się za to zabrać, jakieś wskazówki?
Nie jestem zaawansowany programistycznie, takiego mamy wykładowce ;/
Dzięki z góry za pomoc.
P-79634
mactec
» 2013-03-30 19:04:40
P-79635
Rasoir
Temat założony przez niniejszego użytkownika
» 2013-03-30 19:33:49
Zrozumiałem jedynie że parser przechodzi po całym stringu i jeżeli są to liczby może je dodać do siebie, no ok może jakoś to sam rozgryzłbym jak go użyć ale pozostaje jeszcze kwestia jak nadać słowom wartości liczbowe.
P-79638
Fores
» 2013-03-30 19:44:19
Kiedys probowalem zrobic, tak jak napisales. Wszystko fajnie dzialalo do 10000. Pozniej pojawialy sie problemy przy liczbach typu: 'dwadziescia milionow piecdziesiat tysiecy siedemnascie'.
Do sumowania dobry jest taki parser, ale z zamiana moze byc ciezko.
P-79641
Monika90
» 2013-03-30 19:57:10
Samo przypisanie słowom liczb jest dość proste, można użyć std::map, albo std::unordered_map, przykład:
C/C++
std::map < std::string, int > token_values =
{
    { "jeden", 1 }, { "dwa", 2 }, { "sto", 100 } //itd.
};

std::cout << token_values[ "sto" ] + token_values[ "jeden" ] << std::endl;
rzecz w tym, że to nie wystarczy.

Do parsowania liczb zapisanych w języku naturalnym chyba najlepiej jest użyć maszyny stanowej. Więc rysujesz sobie duży diagram przejść stanów, jest on duży i skomplikowany, bo gramatyka j. polskiego jest skomplikowana. Jak już masz taki diagram, to bezmyślnie go implementujesz.

Zapytaj się wykładowcy, czy może być po angielsku, było by łatwiej.
P-79642
pekfos
» 2013-03-30 21:46:28
Więc rysujesz sobie duży diagram przejść stanów, jest on duży i skomplikowany, bo gramatyka j. polskiego jest skomplikowana. Jak już masz taki diagram, to bezmyślnie go implementujesz.
Dla nie wiadomo jakiej gramatyki może i jest to najlepsze rozwiązanie.. ;)
P-79648
Monika90
» 2013-03-31 20:20:04
To okazało się prostsze niż sądziłam, oto programik, który parsuje liczby pisane słowami w zakresie od 0 do 999999999999999.
C/C++
#include <algorithm>
#include <sstream>
#include <iostream>

template < class Iter, class Int, class Container, class Func >
bool one_of( const Container & tokens, Func index_to_value, Iter & i, Iter end, Int & value )
{
    if( i < end )
    {
        auto v = std::find( tokens.begin(), tokens.end(), * i );
        if( v < tokens.end() )
        {
            value = index_to_value( v - tokens.begin() );
            ++i;
            return true;
        }
    }
   
    return false;
}

template < class Iter, class Int >
bool p0( Iter & i, Iter end, Int & value )
{
    auto tokens = { "zero" };
    return one_of( tokens,[]( Int i ) { return i; }, i, end, value );
}

template < class Iter, class Int >
bool p1_9( Iter & i, Iter end, Int & value )
{
    auto tokens = { "jeden", "dwa", "trzy", "cztery", "piec", "szesc", "siedem", "osiem", "dziewiec" };
    return one_of( tokens,[]( Int i ) { return i + 1; }, i, end, value );
}

template < class Iter, class Int >
bool p10_19( Iter & i, Iter end, Int & value )
{
    auto tokens = { "dziesiec", "jedenascie", "dwanascie", "trzynascie", "czternascie", "pietnascie", "szesnascie", "siedemnascie", "osiemnascie", "dziewietnascie" };
    return one_of( tokens,[]( Int i ) { return i + 10; }, i, end, value );
}

template < class Iter, class Int >
bool p100_900( Iter & i, Iter end, Int & value )
{
    auto tokens = { "sto", "dwiescie", "trzysta", "czterysta", "piecset", "szescset", "siedemset", "osiemset", "dziewiecset" };
    return one_of( tokens,[]( Int i ) { return( i + 1 ) * 100; }, i, end, value );
}

template < class Iter, class Int >
bool p20_99( Iter & i, Iter end, Int & value )
{
    auto tokens = { "dwadziescia", "trzydziesci", "czterdziesci", "piecdziesiat", "szescdziesiat", "siedemdziesiat", "osiemdziesiat", "dziewiecdziesiat" };
    if( one_of( tokens,[]( Int i ) { return( i + 2 ) * 10; }, i, end, value ) )
    {
        Int v;
        if( p1_9( i, end, v ) )
             value += v;
       
        return true;
    }
    else
         return false;
   
}

template < class Iter, class Int >
bool p1_999( Iter & i, Iter end, Int & value )
{
    bool ok = p100_900( i, end, value );
    Int v;
    if( p1_9( i, end, v ) || p10_19( i, end, v ) || p20_99( i, end, v ) )
    {
        value =( ok ? value + v: v );
        return true;
    }
   
    return ok;
}

template < class Iter, class Int, class Func >
bool multiple( Int scale, const char * form1, const char * form2, const char * form3,
Func subparser, Iter & i, Iter end, Int & value )
{
    Iter go_back = i;
    Int v = 1;
    p1_999( i, end, v );
    if( i < end &&( v == 1 && * i == form1 || v % 10 > 1 && v % 10 < 5 && * i == form2 || v > 4 && * i == form3 ) )
    {
        ++i;
        v *= scale;
        Int v2 = 0;
        subparser( i, end, v2 );
        v += v2;
        value = v;
        return true;
    }
   
    i = go_back;
    return subparser( i, end, value );
}

template < class Iter, class Int >
bool p1_999999( Iter & i, Iter end, Int & value )
{
    return multiple( Int { 1000 }, "tysiac", "tysiace", "tysiecy", p1_999 < Iter, Int >, i, end, value );
}

template < class Iter, class Int >
bool p1_999999999( Iter & i, Iter end, Int & value )
{
    return multiple( Int { 1000000 }, "milion", "miliony", "milionow", p1_999999 < Iter, Int >, i, end, value );
}

template < class Iter, class Int >
bool p1_999999999999( Iter & i, Iter end, Int & value )
{
    return multiple( Int { 1000000000 }, "miliard", "miliardy", "miliardow", p1_999999999 < Iter, Int >, i, end, value );
}

template < class Iter, class Int >
bool p1_999999999999999( Iter & i, Iter end, Int & value )
{
    return multiple( Int { 1000000000000 }, "bilion", "biliony", "bilionow", p1_999999999999 < Iter, Int >, i, end, value );
}

template < class Iter, class Int >
bool parse_number( Iter i, Iter end, Int & value )
{
    return p0( i, end, value ) || p1_999999999999999( i, end, value );
}

std::vector < std::string > tokenize( const char * str )
{
    std::istringstream in( str );
    std::vector < std::string > tokens;
    std::string token;
    while( in >> token )
         tokens.push_back( std::move( token ) );
   
    return tokens;
}

int main()
{
    std::string line;
    std::getline( std::cin, line );
    const auto tokens = tokenize( line.c_str() );
    long long value = - 1;
    if( parse_number( tokens.begin(), tokens.end(), value ) )
         std::cout << value << std::endl;
    else
         std::cout << "not a number" << std::endl;
   
}

przykładowa sesja

C:\C\tests>g++ -std=c++11 -O2 test.cpp

C:\C\tests>a
dwiescie piecdziesiat osiem bilionow piecset siedemdziesiat piec miliardow piecset czterdziesci dziewiec milionow dziewiecset czterdziesci jeden tysiecy trzysta dziewiecdziesiat siedem
258575549941397

Ale uwaga! Pisane na szybko, mogą być w nim bugi, trzeba gruntownie przetestować, dodać polskie litery, itp.
P-79683
Rasoir
Temat założony przez niniejszego użytkownika
» 2013-04-01 19:55:05
@Up bardzo dziękuję za pomoc niestety w moim Code:blocks'sie się to nie kompiluje ;] i nic z tego nie rozumiem. Z tymi parserami mam pierwszy raz do czynienie. Postaram się po czytać i zrozumieć jakoś ;] liczyłem bardziej na pomoc jak ma to zrobić totalny nowicjusz ;]. Tak czy siak dziękuje za pomoc.
P-79743
« 1 » 2
  Strona 1 z 2 Następna strona