Для начала, покажу как выглядели данные в самом Excel.
Для начала, я перевел их в текстовый формат средствами самого Excel. Нажал "Файл"-"Сохранить как..."-"Тип файла"-"Текстовые файлы (с разделителями табуляции) (*.txt)".
На выходе получил текстовый файл.
Отлично. Самое легкое позади. Теперь нужно писать собственно, сам парсер.
Для начала посмотрим на то, что должно получиться.
Это массив объектов JavaScript, одно из полей которого — массив из трех элементов. Не трудно заметить что для каждой модели UPS создавалось столько объектов, сколько временных промежутков. Для каждого временного промежутка давалось три значения (три элемента конечного массива). Они берутся из первой, второй и третьей таблицы.
Не буду утомлять техническими тонкостями задачи. Просто покажу как я парсил эти данные и приводил их в нужный вид.
Для начала, я разбил все данные на три блока. Для 1.67В, 1.70В и 1.75В.
sub parse {
my $text = shift; #ловим текст
my @blocks; #здесь будут храниться наши блоки
my @times; #это массив доступных значений времени (горизонтальная ось)
my @lines = split /\r?\n\r?/, $text; #разбиваем данные на строки
my $block=''; #один блок
my @models; #здесь будем хранить доступные модели UPS
my $first=1; #Это просто флаг, который не даст добавить доступные модели 3 раза.
foreach my $l (@lines) {
if(scalar @times ==0 && $l=~/^Watts/) { #Если мы еще не собрали доступные времена и строка начинается с Watts
(undef,@times) = split /\t/, $l; #разбиваем строку по табуляции, отбрасываем первое значение
}
next if($l =~ /^Watts/ || $l=~/VPC/); #пропускаем незначащие строки
if($l eq '') { #если пустая строка, то блок закончен
push @blocks, $block; #сохраняем его
$block=''; #обнуляем
$first--;
next;
}
if($first) { #если это первый блок
my ($model) = $l =~ /^(.*?)\t/; #находим имя модели
push @models, $model; #собираем в массив по порядочку
}
$block .= "$l\n";
}
push @blocks, $block; #не забудем третий блок.
}
Все. Теперь у нас есть три блока данных, которые очищены от лишних строк и изолированы друг от друга, массив доступных временных промежутков и массив доступных моделей.
Теперь нужно распарсить полученные блоки, чтобы создать структуру данных, которую можно будет легко и удобно обойти и создать нужную нам базу данных на JavaScript.
my $ups; #Наша структура
my @VPC = ('1.67', '1.70', '1.75'); #Доступные значения напряжения окончания разряда
for(my $blo=0; $blo<=$#blocks; $blo++) { #номер блока нам важен для связи с
my $block = $blocks[$blo];
my $vpc = $VPC[$blo];
my @lines = split /\n/, $block;
foreach my $l (@lines) {
my ($name, @values) = split /\t/, $l; #получаем имя модели и значения мощности
$ups->{$name}->{$vpc} = {};
for(my $i=0; $i<=$#values; $i++) { #количество значений равно количеству времен
$values[$i] =~ s/,/\./; #форматируем числа для JS. Было 12,3 стало 12.3
$ups->{$name}->{$vpc}->{$times[$i]} = $values[$i]; #Окончательно формируем структуру
}
}
}
Вот. Самое сложное в парсинге — это создать удобную структуру данных. У меня она трехмерная. Зная название модели, напряжение окончания разряда (VPC) и нужное время работы, мы получим значение мощности нагрузки.
Все. Все данные распарсили, осталось только вывести их в правильном виде.
my @result; #соберем все в массив. Так быстрей и экономней
foreach my $name (@models) { #важно соблюдать порядок вывода моделей от младших к старшим
foreach my $t (reverse @times) { #А вот времена даны в порядке убывания. А надо — в порядке возрастания.
my ($v1, $v2, $v3) = reverse @VPC; #VPC тоже даны не в том порядке, в каком надо.
#Здесь я получаю, собственно, три нужных значения для разных VPC одной модели.
my ($v1, $v2, $v3) = ($ups->{$name}->{$v1}->{$t}, $ups->{$name}->{$v2}->{$t}, $ups->{$name}->{$v3}->{$t});
#и формирую строку нужного формата
my $js = qq(\t{"n":"$name", "t":$t, "wtc":[$v1, $v2, $v3]},);
push @result, $js;
}
#Каждую модель отделяю от другой пустой строкой.
push @result, "";
}
#Возвращаем монолитный готовый JS-код
return join "\n", @result;
В итоге получаем:
Это в точности то, что нам надо. За исключением того, что у последнего объекта JS стоит запятая, которая вызовет ошибку в IE. Ее, так и быть, удаляем руками.
Всё! База данных в экзотическом формате JavaScript готова.
Теперь у меня есть парсер, который позволит за минуту (с учетом пересохранения исходных данных из Excel) превратить данные Excel в данные, необходимые калькулятору.
Это избавило меня от ручного труда по вбиванию огоромного количества данных. кроме того, ошибка машинная более заметна в данном случае. А вот ошибка ручного ввода более вероятна и менее заметна в данном случае (можно ввести соседнюю цифру, например, или запутаться откуда списывать, да что угодно!). А главное — в будущем мне не придется вообще тратить время на разработку этого парсера. Как только у меня будут последние данные по этому калькулятору, я тут же смогу его обновить не затратив практически никаких усилий. Так парсер помогает экономить время, которое я лично использовал для написания этого поста:)
Если вас интересуют парсеры данных, пакетная или автоматическая обработка, перевод данных из одного формата в другой — я могу предложить вам создание парсера в короткие сроки и за умеренную плату.
Сам калькулятор, ради которого все делалось, можно посмотреть тут. А вот его движок и база.