2012-06-08 2 views
2

Мне нужно разбить файл на разные.Perl: как разбить файл?

Exmaple (исходный файл):

*****3123123*****RAW 
text1 
text2 
*****2312354***RAW 
text3 

Желаемый результат:

[FILE1.TXT]

*****3123123*****RAW  
text1 
text2 

[file2.txt]

*****312312354***RAW 
text3 

Я попытался использовать split, но я всегда получаю так мне лишние белые символы в массив

open FILE, "<file"; 
@file= <FILE>; 
close FILE; 
@lines = split (/(RAW\n)/, "@file"); 
foreach $value (@lines) { 
    if ($value =~ /[a-z]|[A-Z]|[1-9]/) { 
    print ("$value\n"); 
    } 
} 

Выход:

*****3123123*****RAW 

text1 
text2 

*****312312354***RAW 

text3 

Edit: если я использую печать ("$ значение") вместо печати ("значение $ \ п") это выход (обратите внимание на 1 дополнительное пространство перед значением:

*****3123123*****RAW 
text1 
text2 

*****12354***RAW 
text3 
+1

Разве это не то, что когда вы раскалываете, это не удаляет символы новой строки, поэтому, когда вы добавляете 'print (« $ value \ n »)', вы добавляете дополнительную строку новой строки. Вот почему, похоже, есть лишние пробелы. –

+0

без \ n Я получаю 1 лишнее пробел в начале каждого значения. – user1444482

+0

Дополнительное пространство - это то, что вы интерполируете '@ file' в одну строку, которая по умолчанию вводит пробел между элементами. Обычно лучше читать файл по строкам, если он не очень маленький, но если вы настаиваете на его чтении сразу, вы можете написать '@lines = split (/ (RAW \ n) /, join '', @ file' или slurp все это сразу с помощью 'my $ data = do {local $ /; }; @lines = split (/ (RAW \ n) /, $ data; – Borodin

ответ

1

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

use strict; 
use warnings; 

@ARGV or die "Input file required as command-line parameter\n"; 

my $out; 

while (<>) { 
    if (/(\d+)\*+RAW$/) { 
    open $out, '>', "$1.out" or die $!; 
    select $out; 
    } 
    print $_ if $out; 
} 
+0

Большое вам спасибо. – user1444482

2

Вы могли бы сделать лучше с линии мудр IO:

my $id = 0; 
my $FILE = undef; 

while (<>) { 
    if (/RAW/) { 
     close $FILE if defined $FILE; 
     $id++; 
     my $path = "File$id.txt"; 
     open $FILE, '>', $path or die "Could not open $path: $!"; 
    } 
    print $FILE $_ if defined $FILE; 
} 
close $FILE if defined $FILE; 

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

+0

Пытался запустить скрипт, но ничего не происходит. но никогда не заканчивается, поэтому я должен использовать Ctrl-C. – user1444482

+1

@ user1444482: это решение работает нормально. Он ожидает входной файл в командной строке, как и мой. Если вы его не доставляете, он будет в ожидании ввода с клавиатура. – Borodin

+0

Почему вы создали эту Вики-страницу сообщества? –

0

Вот что я придумал. Я не могу не чувствовать, что это изобретает колесо.

#!usr/bin/perl 
my $fi, $fi2; 
my $line; 
my $i; 
my @lines; 
my @filenameparts; 
my $filename = "file_1.txt"; 

open($fi, "< original.txt"); 
@lines = <$fi>; 
open ($fi2, " > $filename"); 

foreach (@lines) 
{ 
if (($i > 0) and $_ =~ /RAW/) 
{ 
    @filenameparts = split("_", $filename); 
    foreach (@filenameparts) 
    { 
     print "Woooo".$_; 
    } 
    @filenameparts[1] = substr(@filenameparts[1], 0, @filenameparts[1].length() - 5); 
    @filenameparts[1] = ($filenameparts[1] + 1); 
    $filename = @filenameparts[0]."_"[email protected][1].".txt"; 
    print $filename; 
    close($fi2); 
    open ($fi2, " > $filename"); 
    $i = 0; 
    print $fi2 $_; 

} 
else 
{ 
    print $fi2 $_; 
} 
$i++; 

} 
+2

Вы должны привыкнуть добавлять 'use strict' и' использовать предупреждения' в верхней части своих программ Perl. Это выявило бы много проблем с вашим программированием, которые не являются очевидными. Вы также должны помнить, что вы программируете Perl, а не Java, JavaScript или C++ - везде, откуда вы пришли - поскольку '@filenameparts [1] .length()' не получает длину второй строки в массиве, он объединяет вторую строку с длиной '$ _', что совсем не то же самое. – Borodin

+0

Я сердечно соглашаюсь с вами, что мое программирование на Perl оставляет желать лучшего. – PinkElephantsOnParade

+0

Просто пытаюсь помочь вам улучшить :) Кстати, мое решение намного гольфие, чем daxim's: P – Borodin

2
use strictures; 
use File::Slurp qw(read_file write_file); 
my $raw = read_file('raw.txt', binmode => ':raw'); 
my $header = qr/^ (?= [*]+ [0-9]+ [*]+ RAW\n)/msx; 
my @chunks = split $header, $raw; 
# (
#  "*****3123123*****RAW\ntext1\ntext2\n", 
#  "*****2312354***RAW\ntext3" 
#) 
for my $i ([email protected]) { 
    write_file("File$i.txt", {binmode => ':raw'}, $chunks[$i-1]); 
} 
+0

Woah, вы определенно выигрываете гольф в гольф на Perl – PinkElephantsOnParade

+2

Это даже не гольф, это прямолинейный Perl, как пишет опытный программист. В этом нет никаких неясных знаний, только ** помня о возможностях встроенных функций **, таких как [split] (http://p3rl.org/split) и **, используя библиотеки CPAN **, где это необходимо. – daxim

+0

Почему 'binmode'? – Borodin

0

Если вы хотите остаться с кодом вы сделали, то просто просто заменить строку print ("$value\n"); с print ("$value"); и вы его получили ...

Или перед тем print удалить \n с chomp($value); и пребывание с выходом print ("$value\n");.

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