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. #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. |