#!/usr/bin/perl ######################################################################## # # $Id$ # # Copyright (c) 2002 Okunev Igor # ######################################################################## use strict; $^W = 1; if ( defined ( my $i = shift ) ) { print digit_to_money_string( $i ), "\n"; } else { print "Число: " if -t STDIN; while ( defined ( $i = ) ) { chomp $i; print digit_to_money_string( $i ), "\n"; print "Число: " if -t STDIN; } } sub digit_to_money_string { my $digit = shift; local $_; # # Проверка на отрицательность числа # my $sign = 1 if $digit =~ s/^-+//; # # Удаляем нули из начала числа # $digit =~ s#^0+##; my ( $b_dig, $s_dig ) = ( split( m/[,.]/, $digit, 2 ) ); # # Очищаем числа от `лишних' символов ( 100_000,43 ) # if ( defined $b_dig and length $b_dig ) { $b_dig =~ s#[^\d]##sg; } else { $b_dig = 0; } if ( defined $s_dig and length $s_dig ) { $s_dig =~ s#[^\d]##sg; } else { $s_dig = 0; } # # Округляем копейки в большую сторону, если в результате округления # получаем рубль, то приплюсовываем его к b_dig ( рублям ) # if ( sprintf('%0.2f', "0.$s_dig" ) == 1 ) { $b_dig ++; $s_dig = '00'; } else { $s_dig = substr( sprintf('%0.2f', "0.$s_dig" ), 2 ); } my @array = split( //, ( $b_dig || 0 ) ); # # Определяем разрядность числа. # my $class_id = int( scalar ( @array ) / 3); $class_id++ if ( scalar ( @array ) % 3 ); # # Неподдерживаемая разрядность. # return $digit if $class_id > 12; my $digits_name = { 0 => ['ноль', '', '' ], 1 => [['один','одна'], 'десять', 'сто' ], 2 => [['два','две'], 'двадцать', 'двести' ], 3 => ['три', 'тридцать', 'триста' ], 4 => ['четыре', 'сорок', 'четыреста' ], 5 => ['пять', 'пятьдесят', 'пятьсот' ], 6 => ['шесть', 'шестьдесят', 'шестьсот' ], 7 => ['семь', 'семьдесят', 'семьсот' ], 8 => ['восемь', 'восемьдесят', 'восемьсот' ], 9 => ['девять', 'девяносто', 'девятьсот' ], }; my $dec_digits = { 11 => 'одинадцать', 12 => 'двенадцать', 13 => 'тринадцать', 14 => 'четырнадцать', 15 => 'пятнадцать', 16 => 'шестнадцать', 17 => 'семнадцать', 18 => 'восемнадцать', 19 => 'девятнадцать' }; my $digits_class = { '-1'=> [ 1, 'копейка', 'копеек', 'копейки' ], 0 => [ 0, 'рубль', 'рублей', 'рубля' ], 1 => [ 1, 'тысяча', 'тысяч', 'тысячи' ], 2 => [ 0, 'миллион', 'миллионов', 'миллиона' ], 3 => [ 0, 'миллиард', 'миллиардов', 'миллиарда' ], 4 => [ 0, 'триллион', 'триллионов', 'триллиона' ], 5 => [ 0, 'квадриллион', 'квадриллионов', 'квадриллиона' ], 6 => [ 0, 'квинтиллиан', 'квинтиллианов','квинтиллиана'], 7 => [ 0, 'секстиллион', 'секстиллионов','секстиллиона'], 8 => [ 0, 'септиллион', 'септиллионов', 'септиллиона'], 9 => [ 0, 'октилион', 'октлионов', 'октилиона' ], 10 => [ 0, 'нониллион', 'нониллионов', 'ноннилиона'], 11 => [ 0, 'дециллион', 'дециллионов', 'дециллиона' ] }; # # Определяем длину левой `тройки'... # my $id = 0; unless ( ( scalar @array ) % 3 ) { $id = 2; } else { $id = ( ( scalar @array ) % 3 ) - 1; } my $str = ''; my $sub_str = 0; my $tvar = 0; if ( $array[0] == 0 ) { # # Если рублей таки ноль, то так и пишем 'ноль рублей', # если не надо то просто закомнтировать следующую строку... # $str .= $digits_name->{'0'}->[0] . ' ' . $digits_class->{'0'}->[2] . ' '; } else { while ( defined ( $_ = shift @array ) ) { if ( $_ > 0 ) { if ( $_ == 1 and $id == 1 ) { # # Считаем сумму для использования в sub num() # $sub_str += $_ * 10; if ( defined ( $tvar = shift @array ) and $tvar > 0 ) { $str .= $dec_digits->{ $_ . $tvar }; $sub_str += $tvar; $id--; } else { unshift @array, $tvar; if ( ref $digits_name->{$_}->[$id] eq 'ARRAY' ) { $str .= $digits_name->{$_}->[$id]->[$digits_class->{$class_id-1}->[0]]; } else { $str .= $digits_name->{$_}->[$id]; } } } else { # # Считаем сумму для использования в sub num() # $sub_str += ( $_ * ( 10 ** $id ) ); if ( ref $digits_name->{$_}->[$id] eq 'ARRAY' ) { $str .= $digits_name->{$_}->[$id]->[$digits_class->{$class_id-1}->[0]]; } else { $str .= $digits_name->{$_}->[$id]; } } $str .= ' '; } if ( --$id == -1 ) { $id = 2; $class_id--; if ( $sub_str > 0 ) { $str .= num( $sub_str, ( @{ $digits_class->{$class_id} } )[ 1 .. 3 ] ) . ' '; } elsif ( $class_id == 0 ) { $str .= $digits_class->{$class_id}->[2] . ' '; } $sub_str = 0; } } } $str .= $s_dig . ' ' . num( $s_dig, ( @{ $digits_class->{ '-1' } } )[ 1 .. 3 ] ); if ( defined $sign ) { $str = 'минус ' . $str; } $s_dig = substr( $str, 0, 1 ); # # В том случае где оно пользовалось оказалось проще # так, чем через use locale & ucfirst... # if ( $s_dig =~ tr/абвгдеёжзийклмнопрстуфхцчшщъыьэюя/АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ/ ) { substr( $str, 0, 1, $s_dig ); } return $str; } # # Используется при переводе денежного числа в строку прописью.. # sub num { my $d1 = $_[0] % 10; my $d2 = int( ( $_[0] % 100 ) / 10 ); return $_[2] if ( ( $d2 == 1 ) or ( $d1 =~ /[05-9]/ ) ); return $_[1] if ( $d1==1 ); return $_[3]; }