The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Perl" / Оглавление документа

Использование Spreadsheet::WriteExcel

Задача, есть результаты школьных олимпиад. Нужно разослать результаты по школам. Исходные данные лежат в файле в виде:
2#МОК#Федяков#Андрей#9#М#ГОР#ВОРОНЕЖ#УЛ ШЕНДРИКОВА 7#394086#0732 317825#0#0#0#0#0#0#0#0#0#0#0#0
2#МОК#Амшеникова#Наталия#8#М##ВОРОНЕЖ#УЛ ШЕНДРИКОВА 7#394086#0732 317821#0#0#0#2#0#3#5#0#3#5#0#18
2#УЧЕБНО ВОСПИТАТЕЛЬНЫЙ КОМПЛЕКС#Протасов#Виталий#8#М#ГОР#ВОРОНЕЖ#УЛ ГЕРОЕВ СИБИРЯКОВ 5#394051#80732 335836#7#0#7#0#7#0#2#0#7#7#0#37
1#МУНИЦИПАЛЬНЫЙ ЛИЦЕЙ#Головин#Алексей#8#М#ГОР#ВОРОНЕЖ#УЛ ЛИЗЮКОВА 81#394088#0732 137587#7#7#7#7#7#6#7#7#7#7#0#69
0#ЯЗ ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Корж#Дмитрий#11#Б##ВОРОНЕЖ# ВОЛОДАРСКОГО 41#394000#0732 552759#3#8#6#8#7#4#6#0#0#0#0#42
0#ЯЗ ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Ладная#Екатерина#11#Б##ВОРОНЕЖ# ВОЛОДАРСКОГО 41#394000#0732 552759#4#5#4#7#6#3#3#0#0#0#0#32
0#ЯЗ ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Кузнецова#Наталья#11#Б##ВОРОНЕЖ# ВОЛОДАРСКОГО 41#394000#0732 552759#4#5#4#6#6#4#3#0#0#0#0#32
0#ЯЗ ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Де-Жорж#Инна#11#Б##ВОРОНЕЖ# ВОЛОДАРСКОГО 41#394000#0732 552759#4#5#4#6#6#4#3#0#0#0#0#32
0#ЯЗ ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Загонова#Виктория#11#Б##ВОРОНЕЖ# ВОЛОДАРСКОГО 41#394000#0732 552759#4#5#4#8#5#1#3#0#0#0#0#30
0#ГИМНАЗИЯ ИМ А В КОЛЬЦОВА#Гудков#Илья#11#Б#ГОР#ВОРОНЕЖ#УЛ ВОЛОДАРСКОГО 41#394000#0732 552759#4#4#4#6#3#2#3#0#0#0#0#26
2#МОК#Вдовина#Вера#11#Б##ВОРОНЕЖ#УЛ ШЕНДРИКОВА 7#394086#80732 317825#2#6#5#5#2#2#2#0#0#0#0#24
72#ШКОЛА#Холявка#Марина#11#Б##ВОРОНЕЖ# ЮЖНОМОРАВСКАЯ 18#394062#0732 331084#5#6#8#7#9#6#9#0#0#0#0#50
4#СРЕДНЯЯ ШКОЛА#Лукина#Дарья#11#Б#ГОР#ВОРОНЕЖ#БУЛЬВАР ПИОНЕРОВ 14#394038#0732 336762#3#6#6#2#3#3#2#0#0#0#0#25
4#СРЕДНЯЯ ШКОЛА#Кварацхелия#Кристина#11#Б#ГОР#ВОРОНЕЖ#БУЛЬВАР ПИОНЕРОВ 14#394038#0732 336730#3#5#6#3#3#3#0#0#0#0#0#23
...
и т.д.
Сначала это, правда, был файл *.dbf, но его при помощи программы
#!/usr/bin/perl
qx[dbfdump --fs="\x18" --rs="\x19"  olimp.dbf >one.txt];
сделали текстовым, потом perl -i -n -p -e 's!\x18!#!; s!\x19!\n!;' one.txt получили исходный. Нужно сделать рассылку по школам, т.е. отсортировать по городам, по названиям школ и в каждую поместить по пользователю. Выходные данные должны быть в формате excel, т.к. для каждого конверта нужны полный адрес школы и список результатов каждого учащегося. Причем, excel позволяет отдавать на печать файлы постранично, т.е. для каждой школы отдельная страничка и потом удобно все это раскладывать по конвертам, т.е. нужно в файле excel поставить разрывы страниц. Данную задачу реализует следующий скрипт:
#!/usr/bin/perl
use Spreadsheet::WriteExcel;

open F, "<one.txt"; @mass=<F>; close F;

@res1=grep{s!^(.*?#.*?#)(.*?#.*?#.*?#.*?#)(.*?#.*?#)!$3$1$2!} @mass;
@res = grep{!$_{$_}++} 
       map{/^(.*?#.*?#).*?#.*?#/} @res1;

for $gr(@res){
  for $line(@res1){push @{$hash{$gr}{$1}}, $2 
    if $line=~m!$gr(.*?#.*?#)(.*)$!}
}

my $workbook = Spreadsheet::WriteExcel->new("olimp2.xls");
my $sheet = $workbook->addworksheet("all children");
my $format = $workbook->addformat();

$format ->set_text_wrap();
$format->set_bold();
$format->set_size(11);
$format->set_color('blue');
$format->set_align('center');
$sheet->set_column(1, 3, 70);
$sheet->set_row(0,30);
$sheet->activate();

print "end build hash\n";

print "write file...\n";

for $a(sort keys %hash){
  $m=$a; $m=~s!#! !ig; 
  for $key(sort keys %{$hash{$a}}){
    $pb++;
    $u=$key; $u=~s!#! !ig; $i++;
    my $from = join " " => @{[split /#/ => ${$hash{$a}{$key}}[0]]}[4..6];
    $sheet->write($i, 0, "$m $u $from", $format)  if $pb >= 2000;
    for my $test(sort @{$hash{$a}{$key}}){ $i++; $h++;
      my $name = join " " => @{[split /#/ => $test]}[0 .. 3];
      my $nums = join " " => @{[split /#/ => $test]}[7 .. 18];
      $sheet->write($i, 0, "$name $nums") if $pb >= 2000;
    }
    print "$pb\n" if $pb % 1000 == 0;
    $sheet->set_h_pagebreaks($i+1) if $pb >= 2000;
  }
}

print "$m $u $from\n";
print "$h - done\n";
Разберем его работу. Скрипт использует хеши хешей массивов. Строчка @res1=grep{s!^(.*?#.*?#)(.*?#.*?#.*?#.*?#)(.*?#.*?#)!$3$1$2!} @mass; заполняет массив будущими ключи хеша по названию города и улицы, т.к. в городе Саратов вполне может встретится воронежская или ленинградская улица, что смешает результаты. Строчка @res = grep{!$_{$_}++} map{/^(.*?#.*?#).*?#.*?#/} @res1; убирает повторяющиеся элементы для вложенного хеша, т.е. выделяет названия адресов школ. Цикл
for $gr(@res){
  for $line(@res1){push @{$hash{$gr}{$1}}, $2 
    if $line=~m!$gr(.*?#.*?#)(.*)$!}
}
заполняет хеш хешей массивов. Далее требуется чтение man Spreadsheet::WriteExcel и начинаем вывод их хеша и запись файла excel. Строчка my $from = join " " => @{[split /#/ => ${$hash{$a}{$key}}[0]]}[4..6]; расшифровывается как взять нулевой элемент массива ${$hash{$a}{$key}}, потом разрезать его по строчкам в массив по разделителю #: [split /#/ => ${$hash{$a}{$key}}[0]]. Далее взять от массива срез, превратить его в строку, которая будет являться адресом. Одно "но", excel не позволяет ставить более 1000 pagebreaks для каждого открытого файла, и поэтому приходится придумывать различные условия, вроде постраничного вывода. Т.к. надо было сделать быстро, то дабы не писать постраничный вывод обошелся условием if $pb >= 1000 ... etc....

Т.е. следите за обновлениями www.cpan.org! :)


Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру