Perl - начать чтение с определенной строки и получить только первый столбец этой строки до конца - PullRequest
1 голос
/ 25 ноября 2010

У меня есть текстовый файл, который выглядит следующим образом:

Line 1
Line 2
Line 3
Line 4
Line 5
filename2.tif;Smpl/Pix & Bits/Smpl are missing.

Есть 5 строк, которые всегда одинаковы, и на 6-й строке я хочу начать чтение данных. После считывания данных каждая строка (начиная со строки 6) отделяется точкой с запятой. Мне нужно просто получить первую запись в каждой строке (начиная со строки 6).

Например:

Line 1
Line 2
Line 3
Line 4
Line 5
filename2.tif;Smpl/Pix & Bits/Smpl are missing.
filename4.tif;Smpl/Pix & Bits/Smpl are missing.
filename6.tif;Smpl/Pix & Bits/Smpl are missing.
filename8.tif;Smpl/Pix & Bits/Smpl are missing.  

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

filename2.tif
filename4.tif
filename6.tif
filename8.tif

Возможно ли это, и если да, то с чего мне начать?

Ответы [ 3 ]

4 голосов
/ 25 ноября 2010

Используется режим 'Split' (или 'awk') в Perl:

perl -n -F'/;/' -a -e 'next if $. <= 5; print "$F[0]\n";' < data.file

См. « perlrun » и « perlvar ».


Если вам нужно сделать это в функции, которая получает дескриптор файла и количество пропускаемых строк, то вы не будете использовать режим Perl 'autosplit'.

sub skip_N_lines_read_column_1
{
    my($fh, $N) = @_;
    my $i = 0;
    my @files = ();
    while (my $line = <$fh>)
    {
        next if $i++ < $N;
        my($file) = split /;/, $line;
        push @files, $file;
    }
    return @files;
}

Это инициализирует цикл, читает строки, пропускает первые N из них, затем разбивает строку и захватывает только первый результат. Эта строка с my($file) = split... является тонкой; круглые скобки означают, что разделение имеет контекст списка, поэтому оно генерирует список значений (а не количество значений) и присваивает первое значение переменной. Если бы круглые скобки были опущены, вы бы предоставили скалярный контекст для оператора списка, чтобы вы получили количество полей в разделенном выводе, назначенное для $file, а не то, что вам нужно. Имя файла добавляется в конец массива, и массив возвращается. Поскольку код не открыл дескриптор файла, он не закрывает его. Альтернативный интерфейс передаст имя функции (вместо дескриптора открытого файла) в функцию. Затем вы открываете и закрываете файл в функции, опасаясь обработки ошибок.

А если вам нужна помощь с открытием файла и т. Д., То:

use Carp;

sub open_skip_read
{
    my($name) = @_;
    open my $fh, '<', $name or croak "Failed to open file $name ($!)";
    my @list = skip_N_lines_read_column_1($fh, 5);
    close $fh or croak "Failed to close file $name ($!)";
    return @list;
}
2 голосов
/ 25 ноября 2010
#!/usr/bin/env perl
#
# name_of_program - what the program does as brief one-liner
#
# Your Name <your_email@your_host.TLA>
# Date program written/released
#################################################################

use 5.10.0;

use utf8;
use strict;
use autodie;
use warnings FATAL => "all";

#  ⚠ change to agree with your input: ↓
use open ":std" => IN    => ":encoding(ISO-8859-1)",
                   OUT   => ":utf8";
#  ⚠ change for your output: ↑ — *maybe*, but leaving as UTF-8 is sometimes better

END {close STDOUT}

our $VERSION = 1.0;

$| = 1;

if (@ARGV == 0 && -t STDIN) {
   warn "reading stdin from keyboard for want of file args or pipe";
}

while (<>) {
    next if 1 .. 5;
    my $initial_field = /^([^;]+)/ ? $1 : next;
    #    ╔═══════════════════════════╗
    #   ☞ your processing goes here ☜
    #    ╚═══════════════════════════╝
} continue {
    close ARGV if eof;
}

__END__
2 голосов
/ 25 ноября 2010

Ужасно, но, зачитайте пустые строки, а затем разделитесь; для остальных из них.

my $logfile = '/path/to/logfile.txt';

open(FILE, $logfile) || die "Couldn't open $logfile: $!\n";

for (my $i = 0 ; $i < 5 ; $i++) {
   my $dummy = <FILE>;
}

while (<FILE>) {
   my (@fields) = split /;/;
   print $fields[0], "\n";
}

close(FILE);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...