Задача.
Есть основной файл и файлы шаблонов, причем все имеют расширение csv. Как можно быстро обработать файл на основе шаблонов?
В php5 есть специализированные функции str_getcsv(), fgetcsv() и fputcsv(), которые адаптированы для работы с такого рода файлами. Но можно обойтись и без этих функций. Во время такого рода манипуляций часто сталкивался с ошибками, которые необходимо учитывать - извлекаемые значения из массивов порой содержали неожиданные знаки табуляции, или строка состояла из символов в перемешку с NULL-символами... Поэтому обращение к шаблонам, разобранных на соответствующие массивы, сопровождались казусами, например - использование неопределенных массивов. Отсюда вывод - нужно использовать trim() как фильтр от таких "неожиданностей" и isset() - как подобие отлова исключительной ситуации с попыткой извлечения значения из массива по неопределенному индексу. В остальном все сработало неплохо :)
Пример (download).
<?php ## manipulation with csv-files (base of device tags)
/***********open source and target csv-files*****************************************
// 13010000.csv
$f = fopen("c:\\php\\scripts\\in\\devices.csv", "rb");
// pattern.csv
$pattern = fopen("c:\\php\\scripts\\templates\\pattern.csv", "rb");
// BTDevices_Adresses.csv
$btdevices = fopen("c:\\php\\scripts\\templates\\BTDevices_Adresses.csv", "rb");
// output.csv
$output = fopen("c:\\php\\scripts\\out\\output.csv", "wb");
//***********transfer data from file to string and clean all NULL************************
function transfer($file) {
// read file to $hash from $buffer. Take max length of Double Integer
while(($buffer = fgets($file, 64536)) !== FALSE) {
$hash[] = $buffer;
}
// sort $hash and clean from '\0'
for($k = 0; $k < count($hash); $k++) {
// cleaned massive
$strbox[$k] = " ";
for($i = 0, $j = 0; $j < strlen($hash[$k]); $j++) {
if($hash[$k][$j] == "\0") {
continue;
}
else {
$strbox[$k][$i] = $hash[$k][$j];
$i++;
}
}
}
// Clean buffer
$buffer = NULL;
return $strbox;
}
//**********transfer all files****************************************************
// device.csv
$box_f = transfer($f);
// pattern.csv
$box_patt = transfer($pattern);
// BTDevices_Adresses.csv
$box_btd = transfer($btdevices);
// create accessories arraies
//********$template_array ********Array[:TEMPLATES][$i] = Signal Alias ***********
// parse string into an array
for($i = 0; $i < count($box_patt); $i++) {
$temp[] = explode(",", $box_patt[$i]);
}
// create Array[:TEMPLATES][$i] = Signal Alias
$template_array = Array();
for($col = 0; $col < count($temp[0]); $col++) {
$template_name = NULL;
$template_name = $temp[0][$col];
for($str = 1; $str < count($temp); $str++) {
$tem = NULL;
$tem = $temp[$str][$col];
$template_array[$template_name][] = $tem;
}
}
//************************************************ $btd *********************** Array[:Tagname] = ShortDesc *****************
// create Array[:Tagname] = ShortDesc
// ...немного схалтурил, так как нужно искать по индексам или иначе.
// Сие допустимо, так как структура файла - исходника нам известна
// parse string into an array. $i = 0 - header string have to miss
for($i = 1; $i < count($box_btd); $i++) {
list(, $shortdesc,,,,,,, $tagname) = explode(",", $box_btd[$i]);
$btd[$tagname] = $shortdesc;
$shortdesc = NULL;
$tagname = NULL;
}
//**********$engunits ****************Array[:Tagname] = EngUnits *****************
// create Array[:Tagname] = EngUnits
// ...немного схалтурил, так как нужно искать по индексам или иначе.
// Сие допустимо, так как структура файла - исходника нам известна
// parse string into an array. $i = 0 - header string have to miss
for($i = 1; $i < count($box_btd); $i++) {
list(,,,, $engunit,,,, $tagname) = explode(",", $box_btd[$i]);
$engunits[$tagname] = $engunit;
$engunit = NULL;
$tagname = NULL;
}
// create main array ($arr is base on input file)
//**********************$arr ****************************************************
// parse string into an array
for($i = 0; $i < count($box_f); $i++) {
$arr[] = explode(",", $box_f[$i]);
}
print_r($arr);
//***********************processing $arr and rewrite needly values*********************
// for change values of $arr in loop we get array by ref
$count_row = 0;
foreach($arr as &$row) {
foreach($row as $elem => $value) {
// ':TEMPLATE'
if((strpos($value, ':TEMPLATE')) !== false) {
// reset array
$signal_aliases = Array();
// find template name of device
list(,$templ) = explode("=", $value);
$trimmed_templ = trim($templ);
// defined signal aliases of find template
// $template_array is array that content link :TEMPLATE -> Array(Template signal aliases)
if(isset($template_array[$trimmed_templ])) {
$signal_aliases = $template_array[$trimmed_templ];
}
}
// ':Tagname'
if((strpos($value, ':Tagname')) !== false) {
// initialization
$index = 1;
$stop = true;
// reset array $tags
$tags = Array();
//
while($stop) {
$tag = trim($arr[$count_row + $index][$elem]);
if($tag !== "") {
$tags[] = $tag;
$index++;
}
if($tag == "") {
$stop = false;
}
}
}
// 'ShortDesc'
if((strpos($value, 'ShortDesc')) !== false) {
// initialization
$position = $count_row + 1;
$indexx = 0;
while($indexx < count($tags)) {
$tag_item = trim($tags[$indexx]);
if(isset($btd[$tag_item])) {
$short_desc = trim($btd[$tag_item]);
$arr[$position + $indexx][$elem] = $short_desc;
}
$indexx++;
}
}
// 'Signal_alias.Desc'
if((strpos($value, '.Desc')) !== false) {
// find index field 'ShortDesc'
list($item,) = explode(".", $value);
$item = trim($item);
//
if(in_array($item, $signal_aliases)) {
$pos = $count_row + 1;
$indexxx = 0;
while($indexxx < count($tags)) {
$new_tag_item = trim($tags[$indexxx]);
if(isset($btd[$new_tag_item])) {
$new_item = ". ".str_replace("_", " ", $item).".";
$item_for_push = $btd[$new_tag_item].$new_item;
$arr[$pos + $indexxx][$elem] = $item_for_push;
}
$indexxx++;
}
}
}
}
$count_row++;
}
//**************transfer from massive to string and write to output csv-file*****************
// for catch mini bug 'ая;'. It`s may be control symbols
$str = ltrim(implode(",", $arr[0]), "ая;");
fputs($output, $str);
// build output file
for($i = 1; $i < sizeof($arr); $i++) {
$str = implode(",", $arr[$i]);
fputs($output, $str);
}
//***********************close handles of source and target csv-files*********************
fclose($f);
fclose($pattern);
fclose($btdevices);
fclose($output);
?>