2009-04-21 2 views
2

Предположим, у меня есть текстовый файл с разделителями табуляции, который содержит данные, расположенные в столбцах (с заголовками).Есть ли модуль Perl для разбора столбчатого текста?

Возможно, что разные столбцы могут быть «сложены» в «рабочий лист», например, есть разделитель (который может или не может быть заранее известен), который позволяет размещать разные столбцы по вертикали.

Есть ли модуль Perl, который облегчает разбор столбчатых данных в этом текстовом файле в структуру данных (например, хеш-таблицу с ключом, являющимся заголовком столбца, а значение является массивом сканеров данных столбцов)?

EDIT Под слоем «stacked» я имею в виду, что столбец текста может содержать несколько отдельных «векторов» данных, каждый из которых имеет разные заголовки и разную длину. По общему признанию, это усложняет синтаксический анализ.

EDIT Я честно не знаю, где такое замешательство. Тем не менее, вот пример:

header_one\theader_three 
data_1\tdata_7 
data_2\tdata_8 
data_3\tdata_9 
\tdata_10 
header_two\tdata_11 
data_4\theader_four 
data_5\tdata_12 
data_6\tdata_13 
\tdata_14 

Сценарий бы превратить это в хэш-таблицу с четырьмя ключами: header_one, header_two, header_three и header_four, каждая клавиша ссылки ссылочный массив Указав на data_n элементов расположенных под заголовком.

+0

Вам, вероятно, придется показать пример ... Мне сложно визуализировать. – Tanktalus

+0

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

+0

ПОКАЗАТЬ ПРИМЕР! Если вы хотите, чтобы кто-нибудь придумал что-то, что сработает. –

ответ

2

Я думаю, что это близко к тому, что вы говорите. Если количество столбцов изменяется, то вход обрабатывается так, как если бы это была другая таблица. Этот код можно было бы легко изменить, чтобы распознать какой-либо другой маркер (например, строку равных знаков) вместо использования столбцов.

#!/usr/bin/perl 

use strict; 
use warnings; 

use Text::CSV_XS; 

#setup the parser, here we want tab separated and we allow 
#loose quoting, so qq/foo\t"bar\tbaz"\tquux/ is 
#("foo", "bar\tbaz", "quux") 
my $p = Text::CSV_XS->new(
    { 
     sep_char   => "\t", 
     allow_loose_quotes => 1, 
    } 
); 

my @stacked; 
my $cur = 0; 
while (<>) { 
    $p->parse($_) or die $p->error_input; 
    my @rec = $p->fields; 
    #normal case, just add the record to the last 
    #section in @stacked 
    if (@rec == $cur) { 
     push @{$stacked[-1]}, \@rec; 
     next; 
    } 
    #if the number of columns don't match then 
    #we have a new section 
    push @stacked, [\@rec]; 
    $cur = @rec; #set the new number of columns 
} 

for my $table (@stacked) { 
    print "header: ", join("::", @{$table->[0]}), "\n"; 
    for my $i (1 .. $#$table) { 
     print "data: ", join("::", @{$table->[$i]}), "\n"; 
    } 
    print "\n"; 
} 
2

Я бы начал с DBD::CSV, если возможно, хотя ваше «сложное» требование (которое я не совсем понимаю), вероятно, потребует некоторого ручного анализа, используя Text::CSV_XS.

Не обманывайтесь их именами - они могут анализировать любые разделители, а не только запятые.

-1

не очень гладко, но я делал это так:

 my $recordType = unpack("A3", $_); 

     if ($recordType eq "APT") 
     { 
      $currentKey = parseFAAAirportAirportRecord($_); 
     } 
     elsif ($recordType eq "ATT") 
     { 
      parseFAAAirportAttendenceRecord($currentKey, $_); 
     } 
     elsif ($recordType eq "RWY") 
     { 
      parseFAAAirportRunwayRecord($currentKey, $_); 
     } 
     elsif ($recordType eq "RMK") 
     { 
      parseFAAAirportRemarkRecord($currentKey, $_); 
     } 
... 
sub parseFAAAirportAirportRecord($) 
{ 
    my ($line) = @_; 

    my ($recordType, $datasource_key, $type, $id, $effDate, $faaRegion, 
     $faaFieldOffice, $state, $stateName, $county, $countyState, 
     $city, $name, $ownershipType, $facilityUse, $ownersName, 
     $ownersAddress, $ownersCityStateZip, $ownersPhone, $facilitiesManager, 
     $managersAddress, $managersCityStateZip, $managersPhone, 
     $formattedLat, $secondsLat, $formattedLong, $secondsLong, 
     $refDetermined, $elev, $elevDetermined, $magVar, $magVarEpoch, $tph, 
     $sectional, $distFromTown, $dirFromTown, $acres, 
     $bndryARTCC, $bndryARTCCid, 
     $bndryARTCCname, $respARTCC, $respARTCCid, $respARTCCname, 
     $fssOnAirport, $fssId, $fssName, $fssPhone, $fssTollFreePhone, 
     $altFss, $altFssName, 
     $altFssPhone, $notamFacility, $notamD, $arptActDate, 
     $arptStatusCode, $arptCert, 
     $naspAgreementCode, $arptAirspcAnalysed, $aoe, $custLandRights, 
     $militaryJoint, $militaryRights, $nationalEmergency, $milUse, 
     $inspMeth, $inspAgency, $lastInsp, $lastInfo, $fuel, $airframeRepairs 
, 
     $engineRepairs, $bottledOyxgen, $bulkOxygen, 
     $lightingSchedule, $tower, $unicomFreqs, $ctafFreq, $segmentedCircle, 
     $lens, $landingFee, $isMedical, 
     $numBasedSEL, $numBasedMEL, $numBasedJet, 
     $numBasedHelo, $numBasedGliders, $numBasedMilitary, 
     $numBasedUltraLight, 
     $numScheduledOperation, $numCommuter, $numAirTaxi, 
     $numGAlocal, $numGAItinerant, 
     $numMil, $countEndingDate, 
     $aptPosSrc, $aptPosSrcDate, $aptElevSrc, $aptElevSrcDate, 
     $contractFuel, $transientStorage, $otherServices, $windIndicator, 
     $icaoId) = 
     unpack("A3 A11 A13 A4 A10 A3 A4 A2 A20 A21 A2 A40 " . 
     "A42 A2 A2 A35 A72 A45 A16 A35 A72 A45 A16 A15 A12 A15 A12 A1 A5 A1 " . 
     "A3 A4 A4 A30 A2 A3 A5 A4 A3 A30 A4 A3 A30 A1 A4 A30 A16 A16 " . 
     "A4 A30 A16 A4 " . 
     "A1 A7 A2 A15 A7 A13 A1 A1 A1 A1 A18 A6 A2 A1 A8 A8 A40 A5 A5 A8 " . 
     "A8 A9 A1 A42 A7 A4 A3 A1 A1 A3 A3 A3 A3 A3 A3 A3 " . 
     "A6 A6 A6 A6 A6 A6 A10" . 
     "A16 A10 A16 A10 A1 A12 A71 A3 A7", $line); 
Смежные вопросы