2014-02-15 3 views
2

Я новичок в PERL, и я пытаюсь взять файл (это на самом деле .idx файл), который отформатирован как этотКак написать каждую строку текстового файла в строку CSV

Monday  Foo Name    43212  
Tuesday  Name Foo Foo   43252 
Tuesday  Name     50322 
Wednesday Foo Name    53221 
Thursday  Foo Bar Foo Name  24353 

и I хотите вывести его как файл csv. Файл должен выглядеть так же, как в CSV-формате, чтобы Excel мог его прочитать. Кроме того, я хочу, чтобы строки, которые во вторник должны быть включены, чтобы файл CSV будет выглядеть

Tuesday  Name Foo Foo  43252 
Tuesday  Name    50322 

В Excel только. У меня также есть несколько файлов idx в формате formYYYY_Q.idx, где YYYY относится к году и Q относится к кварталу. Я хотел бы перебрать все файлы .idx, которые у меня есть, и создать один большой CSV-файл с только строками в каждом файле .idx с Tuesday в начале. Код, который я до сих пор является

#!/usr/bin/perl 

use warnings; 
use strict; 
use Text::CSV; 

my $csvfile= Text::CSV->new({binary=>1,auto_diag=>1}); 
$csvfile->column_names("Day","Name","Number"); 

my @datalines; 
my $idxfile="form1994_1.idx"; 

open(INFILE, "< $idxfile") or die $!; 
open(my $outfile, "> Master.csv") or die $!; 

while(<INFILE>){ 

     if(/^Tuesday/){ 

      chomp($_); 
      push(@nsarlines, $_); 

    } 

} 

Когда я заменить открытую команду с open(OUTFILE, "> Master.txt") or die $!; и включить это в последней строке кода за пределами время цикла:

print OUTFILE map {"$_ \n"} @nsarlines; 

файл Master.txt выглядит внешний вид как я хочу, чтобы

Tuesday  Name Foo Foo  43252 
Tuesday  Name    50322 

Однако, если я использую открытую команду, как написано выше делать что-то подобное вне времени цикла:

$csvfile-> print($outfile, \@test); 

Я получаю CSV файл со всей $_ строки, которая одна строка .idx файла в каждой ячейке файла Master.csv. Мне трудно понять, как сделать perl make каждый из .idx строк CSV строки WIHTOUT вручную, вставляя запятые в $_ (не элегантный или желательный вариант).

Второе, что мне нужно сделать, это иметь файлы formYYY_Q.idx все в одном каталоге, и я хотел бы автоматически пройти через каждый, вытащить строки, которые начинаются со вторника, и добавить их в файл Master.csv (или, скорее, все это и напишите файл Master.csv один раз в конце). Думаю, File::Find может это сделать, но я не смог понять, как его использовать.

Благодарим за помощь.

+0

Почему вы не хотите вставлять запятые? csv - это аббревиатура Comma Separated Values. Вы можете сделать это легко с помощью 'split/\ s + /' и 'join ',' '. Я буду честен, я не вижу причины использовать модуль для записи файлов csv. Чтение, да. Письмо, нет. –

+0

@avitevet В фактическом файле есть переменные 'Fooname' разных слов. Это может быть «Company Foofirm», а другой может быть «Hold Foofirm Parters». Если я использую 'split/\ s + /', он поместит запятую во всю область, в моих данных будет пробел. Так что я получу во вторник, Холдинг, Foofirm, Partners, 43252, а не во вторник, Холдинг Foofirm Partners, 43252 ". И нет регулярной единой картины того, сколько слов составляют название компании. –

+1

Если вы не хотите обрабатывать свои строки, но просто перепечатывайте их, вы должны просто использовать grep: 'grep"^Tuesday "form1994_1.idx' – TLP

ответ

2

Существует 2 способа использования File :: Find. Один из них - вы используете функцию wanted для добавления данных о файлах в глобальный список/очередь/переменную, затем обрабатываете данные после вызова find. Другой способ - выполнить всю обработку в функции wanted.

Мне лично не нравится использование глобалов для передачи данных из функций, но, к сожалению, с файлом :: Найти, что это ваш вариант. Вот пример, где они делают это: http://www.perlmonks.org/?node_id=217378. В этом примере они используют хэш% size для передачи данных из анонимной функции wanted. Вероятно, это ваш лучший вариант, вы должны добавить соответствующие имена файлов в глобальный список, а затем перебирать список, записывая данные из каждого файла в CSV.

Другой вариант - выполнить вашу обработку в функции wanted.Но опять же это субоптимально, потому что вам нужно будет использовать глобальные переменные для передачи информации вwanted функция открытого файла CSV.

Другой вариант, предполагая, что все ваши .IDX-файлы могут быть в том же каталоге (а не в том же каталоге), должны использовать функции readdir opendir &. http://perldoc.perl.org/functions/readdir.html

my $dh; # directory handle 
opendir($dh, $your_dir) || die $!; 
my @idxfiles = grep {/\.idx$/} readdir($dh); 
closedir($dh); 

foreach my $idxfile (@idxfiles) { 
    open(INFILE, "< $idxfile") or die $!; 
    ... the rest of your code ... 
} 
1

Комбинированной часть коды операционной и некоторых из avitevet-х лет, и пришел с этим:

#!/usr/bin/perl 
use warnings; 
use strict; 

opendir(DIR, ".") or die $!; 
my @idxfiles = sort(grep {/\.idx$/} readdir(DIR)); 
closedir(DIR); 

open(OUT, "> Master.csv") or die $!; 
foreach my $idx (@idxfiles) { 
    open(F, "$idx") or die $!; 
    while (<F>) { 
    if (m/^Tuesday/) { 
     my @fields = split(/\s+/); 
     my $day = shift(@fields); # grab the first one 
     my $zip = pop(@fields); # grab the last one; 
     my $middle = join(" ", @fields); # merge the rest back together 
     print OUT "$day,$middle,$zip\n"; 
    } 
    } 
    close(F) 
} 
close(OUT); 
+0

Спасибо за код. Мой фактический файл содержит более трех столбцов. Можно просто использовать 'shift' для работы через все столбцы до последнего, а затем присоединить их все в конце? –

+0

В моем коде строка разбивается на пробелы/пробелы.Поскольку вы указали, что второе поле также может содержать пробелы, мой код работает только в том случае, если вы сдвигаете первый столбец, а затем удаляете последний столбец. Если вы продолжаете перемещаться по столбцам, вы разбиваете второе поле поля везде, где есть пробелы. Если это поле «ТОЛЬКО» с пробелами, вы можете перенести первый и вывести столбцы 3 и выше, оставив вас с «средним значением», показанным выше. – jimtut

0

Я аплодирую четкое описание вашей проблемы и вашей попытку решения!

Учитывая ваш рассказ, в том числе имеющие все ваши IDX файлов в одном каталоге, рассмотрим следующее решение - быть выполнен в * .idx содержащего каталог:

use strict; 
use warnings; 

open my $outfile, '>', 'Master.csv' or die $!; 
print $outfile "Day,Name,Number\n"; 

for my $idxfile (<*.idx>) { 
    next unless $idxfile =~ /^form\d{4}_\d\.idx/; 
    open my $infile, '<', $idxfile or die $!; 

    while (<$infile>) { 
     if (/^Tuesday/) { 
      my ($day, $name, $num) = /(\w+)\s+(.+?)\s+(\d+)/; 
      print $outfile "$day,$name,$num\n"; 
     } 
    } 

    close $infile; 
} 

close $outfile; 

Заголовок первым написанном файл Master.csv. Конструкция <*.idx> представляет собой glob, который генерирует список * .idx-файлов из текущего каталога. Далее, регулярное выражение используется, чтобы гарантировать, что имя файла соответствует вашим спецификациям именования. Если в каталоге находятся только те файлы, которые вы хотите обработать, вы можете удалить эту строку.

Текущий файл idx открывается и обрабатывается. Как и в вашем коде, регулярное выражение используется для проверки «Вторника» в начале строки. Если такая линия встречается, регулярное выражение захватывает три поля:

/(\w+)\s+(.+?)\s+(\d+)/ 
^^^ ^^
    | | | | | 
    | | | | + - One+ digits - Number 
    | | | + - One+ whitespaces 
    | | + - One+ any characters (except newline) - Name 
    | + - One+ whitespaces 
    + - One+ 'word' characters - Day 

Эти захваченные поля - запятыми, отделяющих их - записываются в файл Master.csv. Когда текущий файл idx полностью считывается, он закрывается, и следующий файл idx обрабатывается - если есть. Наконец, файл Master.csv закрыт.

Надеюсь, это поможет!

Смежные вопросы