【问题标题】:Perl - Start reading from specific line, and only get first column of it line, until endPerl - 从特定行开始读取,并且只获取该行的第一列,直到结束
【发布时间】:2010-11-24 23:28:13
【问题描述】:

我有一个如下所示的文本文件:

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

这可能吗?如果可以,我从哪里开始?

【问题讨论】:

  • 有可能。你还有代码吗?
  • 是和不是。还不是为了这个 - 但我有 300 多行代码正在尝试实现它。它基本上是我正在尝试实现的一项新功能,用于处理已经存在的文本文件中的文件。
  • 对 ̲a̲l̲l̲ 问题开头的答案是,“在 Perl 中,¿我能做到……吗?”“¡是的!”其中一些继续“是的,但是……”

标签: regex perl filehandle


【解决方案1】:

这使用 Perl 'autosplit'(或 'awk')模式:

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

参见“perlrun”和“perlvar”。


如果您需要在给定文件句柄和要跳过的行数的函数中执行此操作,那么您将不会使用 Perl 的“自动拆分”模式。

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;
}

【讨论】:

  • +1。最佳答案,真的。我必须拯救我大脑中的 perl 部分 :)
  • 如何在脚本中而不是在命令行中编写它,并从已经存在的文件的打开文件句柄中读取?
  • @Jonathan:让我害怕的是 perl 知道要在分隔符周围吞噬你的斜线分隔符。我不知道它会那样做!
  • @tchrist: 见 perl run...不,我的意思是,见 'perlrun'...'-Fpattern 指定在 -a 也有效时分割的模式。该模式可以被 // 、 "" 或 '' 包围,否则它将被放在单引号中。您不能在模式中使用文字空格。在这个例子中我真的不需要斜线。
  • 我越来越近了。我将 open_skip_read 子例程的最后一部分更改为return $list[0];,现在它输出文件名。问题是只返回一个文件名,但结果更多。我需要它来返回它遇到的每一场比赛。
【解决方案2】:
#!/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__

【讨论】:

  • 伙计们,我还是迷路了——** Perl 新手**。我已经有一个包含所有内容的文件。我只需要在我的脚本中打开文件,跳过前 5 行,并在第 5 行之后输出每一行的第一列。
  • @drewsrockhard:这就是我的程序所做的。试试看。
  • 你能举例说明如何运行它以及将“输入文件”放在哪里吗?
  • @drew:您可以像运行任何其他脚本一样运行它。你把你的输入文件放在你喜欢的地方;我不知道它的名字。 perl this_program your_input_fileperl this_program &lt; your_input_filecat your_input_file | perl this_programgzcat your_input_file.gz | perl this_programwget -O - http://remote_url | perl this_program 或相同同类和效果的无数替代公式中的任何一种。
  • 这就是我的意思,我一直在说的是我不需要“脚本”,我需要代码来实现我的程序来读取已经存在的文件。所有您列出的示例显示我正在运行此代码,并且以某种方式将我的文本文件传送给它,反之亦然。 Jonathan 的示例是我可以在我自己的脚本中实现的代码,并且我能够定义我现有的文件。我只是不知道如何使用您的脚本来做到这一点。不过,我非常感谢您的帮助。
【解决方案3】:

有点难看,但是,读出虚拟行然后拆分;其他人。

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);

【讨论】:

  • 这可以写成:my @dummy; @dummy[0..4] = &lt;STDIN&gt;;map {($a) = split /;/;print $a,"\n"} &lt;STDIN&gt;;.
  • 如果我试图从文件中读取,而不是从命令行读取。我有一个位于相对位置的文件(例如,我可以通过 logfile.txt 调用它)。我在阅读它时遇到了麻烦,到目前为止,我的代码正在连续拍摄一个 while 循环,我必须 CTRL+C 退出它。
  • @Diego:Por desgracia, 这行不通,因为您只是在切片分配中为 readline 运算符提供了列表上下文,从而耗尽了输入。剩余的行被丢弃。
  • @drewrockshard 我已编辑答案以打开您的文件 logfile.txt。
  • 谢谢!我也会试试这个 - 我最初最喜欢这个,因为它似乎是所有这些中最简单的。
猜你喜欢
  • 1970-01-01
  • 2011-07-20
  • 2021-04-03
  • 1970-01-01
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
相关资源
最近更新 更多