Разработчику. Сборник рецептов PHP
Задавайте вопросы

Анализ данных, состоящих из полей фиксированной ширины

Вернуться назад

Задача

Необходимо разбить на части записи фиксированной ширины в строке.

Решение

Это делается при помощи функции substr():

$fp=fopen('fixed-width-records.txt','r') or die ("can't open file");
while ($s=fgets($fp,1024)) {

        $fields[1]=substr($s,0,10); // первое поле:первые 10 символов строки

        $fields[2]=substr($s,10,5); // второе поле:следующие 5 символов строки

        $fields[3]=substr($s,15,12); // третье поле:следующие 12 символов строки

// функция обработки полей

        process_fields($fields);
}
fclose($fp) or die("can't close file");

Или функции unpack():

$fp = fopen('fixed width records.txt','r') or die ("can't open file");
while ($s=fgets($fp,1024)) {
        // ассоциативный массив с ключами "title", "author" и
        // "publication_year"
        $fields=unpack('A25title/A14author/A4publication_year',$s);
// функция обработки полей
        process_fields($fields);
} fclose($fp) or die("can't close file");

Обсуждение

Данные, в которых каждому полю выделено фиксированное число символов в строке, могут выглядеть, как этот список книг, названий и дат опубликования:

$booklist=<< Elmer Gantry         Sinclair Lewis1927
The Scarlatti InheritanceRobert Ludlum 1971
The Parsifal Mosaic          Robert Ludlum 1982
Sophie's Choice         William Styron1979
END;

В каждой строке название занимает 25 символов, имя автора – следующие 14 символов, а год публикации – следующие 4 символа. Зная ширину полей, очень просто с помощью функции substr() перенести поля в массив.

$books = explode("\n",$booklist);

for($i=0, $j=count($books); $i < $j; $i++) {
        $book_array[$i]['title']=substr($books[$i],0,25);
        $book_array[$i]['author']=substr($books[$i],25,14);
        $book_array[$i]['publication_year']=substr($books[$i],39,4);
}

Разбиение переменной $booklist на массив строк позволяет применить один код разбора одной строки ко всем строкам, прочитанным из файла. Цикл можно сделать более гибким, определив отдельные массивы для имен полей и их ширины, которые могут быть переданы в анализирующую функцию, как показано в функции pc_fixed_width_substr() примера 1.3.

Пример 1.3. pc_fixed_width_substr()

function pc_fixed_width_substr($fields,$data) {
      $r=array();
        for ($i=0, $j=count($data); $i < $j; $i++) {
          $line_pos=0;
            foreach($fields as $field_name => $field_length) {
            $r[$i][$field_name]=rtrim(substr($data[$i],$line_pos,$field_length));
          $line_pos += $field_length;
}
}
Return $r;
}
$book_fields=array('title' => 25, 'author' => 14, 'publication_year' => 4);
$book_array=pc_fixed_width_substr($book_fields,$books);

Переменная $line_pos отслеживает начало каждого поля, и она увеличивается на ширину предыдущего поля по мере того, как код обрабатывает каждую строку. Для удаления пробельных символов в конце каждого поля предназначена функция rtrim(). Как альтернатива функции substr() для извлечения полей может применяться функция unpack(). Вместо того чтобы задавать имена полей и их ширину в виде ассоциативных массивов, создайте строку форматирования для функции. Код для извлечения полей фиксированной ширины аналогичен функции pc_fixed_width_unpack(), показанной в примере 1.4.

Пример 1.4. pc_fixed_width_unpack()

function pc_fixed_width_unpack($format_string,$data) {
      $r=array();
        for ($i=0, $j=count($data); $i < $j; $i++) {
            $r[$i]=unpack($format_string,$data[$i]);
}
return $r;
}
$book_array=pc_fixed_width_unpack
('A25title/A14author/A4publication_year',$books);

Формат A означает «строку в обрамлении пробелов», поэтому нет необходимости удалять завершающие пробелы с помощью функции rtrim().Поля, перенесенные с помощью какой-либо функции в переменную $book_array, могут быть отображены в виде HTML-таблицы, например:

$book_array=
pc_fixed_width_unpack('A25title/A14author/A4publication_year',$books);
print "<table>\n";
// печатаем строку заголовка
print '<tr><td>';
print join('</td><td>',array_keys($book_array[0]));
print "</td></tr>\n";
// печатаем каждую строку данных
foreach ($book_array as $row) {
        print '<tr><td>';
        print join('</td><td>',array_values($row));
        print "</td></tr>\n";
}
print '</table>\n';

Объединение данных с помощью тегов </td><td> формирует строку таблицы, не включая в нее начальный <td> и заключительный </td> теги. Печатая <tr><td> перед выводом объединенных данных и </td></tr> вслед за выводом объединенных данных, мы формируем полную строку таблицы.
И функция substr(), и функция unpack() имеют одинаковые возможности, если поля фиксированной ширины содержат строки, но функция unpack() является наилучшим решением при наличии полей других типов данных.

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования


Рейтинг Сайтов ДОСКИ.РУ