2011-01-20 3 views
1

Perl Experts - Моя попытка решить мою проблему превращается в много кода, который в PERL кажется, что я приближаюсь к этому правильно. Вот моя проблема:Perl Text Parsing - фиксированная делиметичная структура меняется

У меня есть блок текста (пример ниже), который может иметь переменное количество пробелов между данными столбца. Я использовал простой раскол, но теперь проблема заключается в том, что в столбце «код» теперь содержатся пробелы в данных (я только учёл это в последнем столбце). То, что кажется постоянным (хотя я не имею доступа к структуре источника или не контролирую его) состоит в том, что между столбцами существует минимум 3 пробела (возможно, больше, но не меньше).

Итак, я хотел бы сказать, что мой токен разделителя столбцов - «3 пробела», а затем обрезать данные в каждом, чтобы иметь мои фактические столбчатые данные.

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

Я просто пытаюсь получить значения в 6 переменных.

ПРИМЕЧАНИЕ: COL0 может не иметь значения. COL4 может содержать пробел в данных. COL5 может не содержать значения или данных с пространством. Все фиксированное форматирование выполняется с пробелами (без вкладок или других специальных символов). Чтобы уточнить - столбцы НЕ соответствуют размеру. Один файл может иметь COL4 как 13 символов, другой - COL4 с шириной 21 символ. Или не строго, как заявил другой член SO.

+0

Может столбец начать с другим смещением между каждой строкой? Например. row1 is '| 1 2 3 | '(3 пробела), а row2 -' | 11111 2 3 | '(также 3 пробела, но второй столбец теперь начинается со смещения 4 больше, чем в первой строке из-за того, что первое значение в строке2 настолько велико) – DVK

+0

Нет, размер столбца согласован для всех строк данных за файл. Может различать файлы, но согласовываться внутри файла. – Walinmichi

+0

Действительно ли заголовки столбцов присутствуют? – Svante

ответ

2

Если вы имеете дело со строгими столбчатых данных, как это, unpack, вероятно, что вы хотите:

#!perl 

use strict; 
use warnings; 
use 5.010; 

use Data::Dumper; 

my $data = <<EOD; 
COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 
EOD 

my @lines = split '\n', $data; 
for my $line (@lines) { 
    my @values = unpack("a5 A7 A7 A7 A13 A*", $line); 
    print Dumper \@values; 
} 

Это, кажется, выливать свои значения в @values массив, как вы хотите, но они будут иметь которые вам придется обрезать.

+0

Звучит так, как будто это не может быть ** строгим ** столбчатым данным, но немного нескромным – DVK

+0

Спасибо за этот метод, не знали об этом. Однако другая часть моей задачи - размеры столбцов могут различаться. Вот почему я думал сосредоточиться на токене 3 символа, так как COL4 может не всегда быть шириной 13 символов (файлы данных с COL4 имеют ширину от 13 до 21 символа). – Walinmichi

0

Я знаю, что CanSpice уже ответил (возможно, гораздо лучшее решение), но вы можете установить разделитель ввода с помощью «$ /». Это должно быть сделано в локальной области (возможно, под), поскольку это глобальная переменная, или вы можете увидеть побочные эффекты. Пример:

local $/ = " "; 
$input = <DATAIN>; # assuming DATAIN is the file-handler 

Вы можете обрезать пробелы, используя небольшое небольшое регулярное выражение. См. Пример Wikipedia.

1

Я бы использовал два прохода: в первом найдите те столбцы символов, у которых есть пробел в каждой строке; затем разделите или распакуйте эти индексы. После этого выполняется обрезка пробелов.

Ваш пример:

COL0 COL1 COL2 COL3   COL4 COL5 
    -  4 0.2  1  416489 463455 554 
      1 0.9  1   E1 
    0  3 1.4  14 E97-TEST 1 
    -  1 97.5 396   PASS Good 

000011100001110000111000011100000000001110000000000 

В 1 s в последней строке показывают, какие столбцы являются все пробелы.

+0

Итак, используйте заголовки столбцов, чтобы определить TEMPLATE, а затем передать эти значения в UNPACK? Я собираюсь попробовать это сейчас. – Walinmichi

+0

@Walinmichi: нет, используйте _all_ строки для определения шаблона. – Svante

+0

Не понимаю. Весь файл содержит еще много таких блоков, все разные структуры. У меня есть код, который доводит меня до нужного блока. Я даже знаю конец блока, потому что под каждым блоком есть константа ***** END *******. – Walinmichi

3

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

my @file = <file>; 
chomp @file; 

my $t = ""; 
$t |= $_ foreach(@file); 

$ т будет содержать пробелы в столбцах только там, где всегда были пробелы в этой колонке; другие столбцы будут содержать двоичный мусор.Теперь разделить его спичкой с нулевой шириной, что соответствует некосмическому:

my @cols = split /(?=[^ ]+)/, $t; 

На самом деле мы хотим в ширины колонн для создания формата распаковка():

@cols = map length, @cols; 
my $format = join '', map "A$_", @cols; 

Теперь процесс файл! :

foreach my $line (@file) { 
    my($field, $field2, ...) = unpack $format, $line; 
    your code here... 
} 

(Этот код был только слегка протестирован.)

+0

Мой текстовый блок на самом деле является лишь подмножеством большего файла с множеством таких блоков (все с разными структурами столбцов). Я знаю начало и конец моего блока, не знаю, как попасть в одну строку ... думаю, я могу объединить строки? – Walinmichi

+0

Мне не удалось заставить это работать для меня. С моим ограниченным знанием PERL я не мог понять, где у меня проблемы. Я закончил использовать простой substr, так как с помощью Svante и vmpstr я понял, что заголовки заголовков являются известными константами. Используя это, я смог найти правильный край всех столбцов, а затем подстроить промежуток между ними. С некоторой отделкой я смог получить то, что хочу, с динамическими ширинами столбцов. Я уверен, что этот тип решения лучше, но, как и в случае с PERL, это заставило меня за короткое время решить проблему. Спасибо всем! – Walinmichi