#!/usr/bin/env perl use v5.14; use warnings; use strict; use Encode qw (encode decode); use Spreadsheet::ParseExcel; use Array::Transpose; use List::Util qw (max); use XBase; use locale; use POSIX qw(locale_h); setlocale( LC_CTYPE, "Russian_Russia.866" ); setlocale( LC_COLLATE, 'Russian_Russia.866' ) or die 'locale!'; my $parser = Spreadsheet::ParseExcel->new(); my $fn = shift @ARGV; my $workbook = $parser->parse("$fn"); unless ( defined $workbook ) { die $parser->error(), ".\n"; } # @array_of_rows массив ссылок массивов my @array_of_rows; for my $worksheet ( $workbook->worksheets() ) { #Берем информацию о файле # строки my ( $row_min, $row_max ) = $worksheet->row_range(); # колонки my ( $col_min, $col_max ) = $worksheet->col_range(); # перебираем все значения в таблице for my $row ( $row_min .. $row_max ) { my $row_array = []; my $flag = 0; for my $col ( $col_min .. $col_max ) { my $cell = $worksheet->get_cell( $row, $col ); if ( $cell and $cell->value() ) { push $row_array, $cell->value(); ++$flag; } else { push $row_array, undef; } } push @array_of_rows, $row_array if $flag; } } #количество строк в таблице, имеющих хотя бы одно значение my $count_of_rows = $#array_of_rows; # массив данных необходимых для формирования файла выплаты my @array_of_payment_data; # транспонируем двухмерный массив для перемещения столбцов в массивы @array_of_rows = transpose( \@array_of_rows ); # хеш счётчиков данных определенного типа my $hash_of_counts = {}; # считаем количество совпадений для счета в каждом столбце for ( my $i = 0 ; $i <= $#array_of_rows ; $i++ ) { $hash_of_counts->{"$i"} = 0; for ( @{ $array_of_rows[$i] } ) { if (defined) { $hash_of_counts->{"$i"}++ if (/^\s*\d{20}\s*$/); } } } # выясняем в каком столбце больше всего совпадений с шаблоном счета my $deposit_count_max = max map { $hash_of_counts->{"$_"} } sort keys %$hash_of_counts; #меняем местами ключ и значение хеша в отдельный хеш my %reverse = reverse %$hash_of_counts; my $deposit_column = $reverse{"$deposit_count_max"}; # обнуляем хеш счетчик $hash_of_counts = {}; # выясняем совпадение по сумме for ( my $i = 0 ; $i <= $#array_of_rows ; $i++ ) { $hash_of_counts->{"$i"} = 0; for ( @{ $array_of_rows[$i] } ) { if (defined) { $hash_of_counts->{"$i"}++ if /^\s*(\d+\.\d{1,2})\s*$/; } } } # выясняем в каком столбце больше всего совпадений с шаблоном суммы my $summ_count_max = max map { $hash_of_counts->{"$_"} } sort keys %$hash_of_counts; %reverse = reverse %$hash_of_counts; my $summ_column = $reverse{$summ_count_max}; $hash_of_counts = {}; # выясняем совпадение по фио for ( my $i = 0 ; $i <= $#array_of_rows ; $i++ ) { $hash_of_counts->{"$i"} = 0; for ( @{ $array_of_rows[$i] } ) { if (defined) { $hash_of_counts->{"$i"}++ if /^\s*(\w+\s*\w*)\x20+(\w+\s*\w*)\x20+(\w+\s*\w*\s*)$/; } } } # выясняем в каком столбце больше всего совпадений с шаблоном фио my $fio_count_max = max map { $hash_of_counts->{"$_"} } sort keys %$hash_of_counts; %reverse = reverse %$hash_of_counts; my $fio_column = $reverse{$fio_count_max}; #переносим счет, сумму, фио в отдельный массив для последующей обработки for ( my $i = 0 ; $i <= $count_of_rows ; $i++ ) { $array_of_payment_data[$i]->{'deposit'} = ( defined( $array_of_rows[$deposit_column][$i] ) and $array_of_rows[$deposit_column][$i] =~ /^\s*(\d{20})\s*$/ ) ? $1 : undef; $array_of_payment_data[$i]->{'value'} = ( defined( $array_of_rows[$summ_column][$i] ) and $array_of_rows[$summ_column][$i] =~ /^\s*(\d+\.?\d{0,2}?)\s*$/ ) ? $1 : undef; ( $array_of_payment_data[$i]->{'f'}, $array_of_payment_data[$i]->{'n'}, $array_of_payment_data[$i]->{'p'} ) = ( defined( $array_of_rows[$fio_column][$i] ) and $array_of_rows[$fio_column][$i] =~ /^\s*(\w+\x2D*\s*\w*)\x20+(\w+\x2D*\s*\w*)\x20+(\w+\s*\x2D*\w*\s*)$/ ) ? ( encode( 'cp866', $1 ), encode( 'cp866', $2 ), encode( 'cp866', $3 ) ) : ( undef, undef, undef ); } # удаляем данные с хотя бы одним пустым значение и сортируем по фио @array_of_payment_data = sort { $a->{'f'} cmp $b->{'f'} or $a->{'n'} cmp $b->{'n'} or $a->{'p'} cmp $b->{'p'} } grep { $_->{'deposit'} and $_->{'value'} and $_->{'f'} and $_->{'n'} and $_->{'p'} } @array_of_payment_data; #Инициализация таблицы dbf my ( $table1, $count1, $differ1 ) = &tabl( substr $fn, 0, -4 ); my $summ1 = 0; #заполняем dbf for (@array_of_payment_data) { $table1->set_record( $count1++, $count1 - $differ1, $_->{'deposit'}, $_->{'f'}, $_->{'n'}, $_->{'p'}, $_->{'value'} ); $summ1 += $_->{'value'}; } $summ1 = sprintf( "%.2f", "$summ1" ); $table1->set_record( $table1->last_record + 1, '', 'ИТОГО:', '', '', '', $summ1 ); $table1->close(); # ----------------------------------------------------------------------------------------------------------------------------------- # #Создание таблицы в формате Сбербанка sub tabl { my $link; my $filename = shift; my $count = 0; $link = XBase->create( "name" => "$filename", "field_names" => [ "A", "B", "C", "D", "E", "F", "G" ], "field_types" => [ "C", "C", "C", "C", "C", "C" ], "field_lengths" => [ 30, 41, 30, 30, 30, 30, 30 ], "field_decimals" => [ undef, undef, undef, undef, undef, undef, undef ] ) or die "can't create file!"; $link->set_record( $count++, 'ОСБ №' ); $link->set_record( $count++, 'К платежному поручению #', '', 'от' ); $link->set_record( $count++, 'Зачисление', "07", "810" ); $link->set_record( $count++, 'Наименование,ОГРН,# банк.счета', 'Организация города','1234567890123', '12345678900987654321' ); $link->set_record( $count++, 'По договору:', '12345678', 'от', '30.09.2010' ); $link->set_record( $count++, '# п/п', 'Номер счета', 'Фамилия', 'Имя', 'Отчество', 'Сумма', 'Примечание' ); return $link, $count, $count; }