Frage

Welchen regulären Ausdruck könnte ich aus irgendeinem Skalar verwenden, um die ersten fünf Zeilen abzugleichen und den Rest zu verwerfen?

War es hilfreich?

Lösung

Seltsame Anfrage, aber das sollte es tun:

#!/usr/bin/perl

use strict;
use warnings;

my $s = join '', map { "$_\n" } 1 .. 9;

my ($first) = $s =~ /^((?:.*\n){0,5})/;
my ($last) = $s =~ /((?:.*\n){0,5})$/;


print "first:\n${first}last:\n$last";

Eine häufigere Lösung wäre ungefähr so:

#!/usr/bn/perl

use strict;
use warnings;

#fake a file for the example    
my $s = join '', map { "$_\n" } 1 .. 9;    
open my $fh, "<", \$s
    or die "could not open in memory file: $!";

my @first;
while (my $line = <$fh>) {
    push @first, $line;
    last if $. == 5;
}

#rewind the file just in case the file has fewer than 10 lines
seek $fh, 0, 0;

my @last;
while (my $line = <$fh>) {
    push @last, $line;
    #remove the earliest line if we have to many
    shift @last if @last == 6;
}

print "first:\n", @first, "last:\n", @last;

Andere Tipps

Warum benutzt du nicht einfach? head dafür?

Sie brauchen keine Regex. Öffnen Sie einfach einen DateiHandle für einen Verweis auf den Skalar und tun Sie die gleichen Dinge, die Sie für eine andere Art von DateiHandle tun würden:

my $scalar = ...;

open my($fh), "<", \ $scalar or die "Could not open filehandle: $!";
foreach ( 1 .. 5 )
    {
    push @lines, scalar <$fh>;
    }
close $fh;

$scalar = join '', @lines;
my ($first_five) = $s =~ /\A((?:.*\n){5})/;
my ($last_five) = $s =~ /((?:.*\n){5})\z/;

Wie Brian sagt, können Sie verwenden head oder tail ziemlich einfach für jedes Problem (erste 5 Zeilen oder letzte 5 Zeilen).

Aber jetzt frage ich mich, ob ich Ihre Frage überhaupt richtig verstehe.Wenn Sie „für jede Art von Skalar“ sagen, meinen Sie damit, dass sich die Datei (aus welchem ​​Grund auch immer) bereits in einem Skalar befindet?

Wenn nicht, denke ich, dass die beste Lösung überhaupt kein regulärer Ausdruck ist.Verwenden $. und lesen Sie die Datei entweder normal oder rückwärts.Um rückwärts zu lesen, können Sie versuchen File::ReadBackwards oder File::Bidirectional.

Menschen fehlen einige wichtige Flaggen:

/(?m)((?:^.*\n?){1,5})/

Ohne die Multi-Line-Flagge wird es nur die erste Zeile betrachten. Auch durch die Herstellung des \n Optional, wir können die ersten fünf nehmen Linien, unabhängig von einer neuen Linie am Ende des fünften.

Warum nicht einfach mit einem Grenzwert aufgeteilt, sondern für diesen Zweck konzipiert:

my @lines = (split /\n/, $scalar, 6)[0..4];

Wenn Sie das als einzelne Skalar mit fünf Zeilen zurück haben möchten, schließen Sie sich damit wieder an:

my $scalar = join('\n', @lines) . "\n";
use strict;


my $line; #Store line currently being read
my $count=$ARGV[1]; # How many lines to read as passed from command line
my @last; #Array to store last count lines
my $index; #Index of the line being stored


#Open the file to read as supplied from command line
open (FILE,$ARGV[0]);
while ($line=<FILE>)
{
    $index=$.%$count;  # would help me in filter just $count records of the file
    $last[$index]=$line; #store this value
}
close (FILE);

#Output the stored lines
for (my $i=$index+1;$i<$count;$i++)
{
    print ("$last[$i]");
}
for (my $i=$0;$i<=$index;$i++)
{
    print ("$last[$i]");
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top