Search for specific lines from a file

2019-09-15 02:05发布

问题:

I have an array that contains the data from a text file.

I want to filter the array and copy some information to another array. grep seems to not work.

Here's what I have

$file = 'files.txt';

open (FH, "< $file") or die "Can't open $file for read: $!";
@lines = <FH>;
close FH or die "Cannot close $file: $!";

chomp(@lines);

foreach $y (@lines){

    if ( $y =~ /(?:[^\\]*\\|^)[^\\]*$/g ) {
        print $1, pos $y, "\n";
    }
}

files.txt

public_html
Trainings and Events
General Office\Resources
General Office\Travel
General Office\Office Opperations\Contacts
General Office\Office Opperations\Coordinator Operations
public_html\Accordion\dependencies\.svn\tmp\prop-base
public_html\Accordion\dependencies\.svn\tmp\props
public_html\Accordion\dependencies\.svn\tmp\text-base

The regular expression should take the last one or two folders and put them into their own array for printing.

回答1:

A regex can get very picky for this. It is far easier to split the path into components and then count off as many as you need. And there is a tool that fits your exact purpose, the core module File::Spec, as mentioned by xxfelixxx in a comment.

You can use its splitdir to break up the path, and catdir to compose one.

use warnings 'all';
use strict;
use feature 'say';

use File::Spec::Functions qw(splitdir catdir);

my $file = 'files.txt';    
open my $fh, '<', $file or die "Can't open $file: $!";

my @dirs;    
while (<$fh>) {
    next if /^\s*$/;  # skip empty lines
    chomp;

    my @all_dir = splitdir $_;

    push @dirs, (@all_dir >= 2 ? catdir @all_dir[-2,-1] : @all_dir);
}
close $fh;

say for @dirs;

I use the module's functional interface while for heavier work you want its object oriented one. Reading the whole file into an array has its uses but in general process line by line. The list manipulations can be done more elegantly but I went for simplicity.

I'd like to add a few general comments

  • Always start your programs with use strict and use warnings

  • Use lexical filehandles, my $fh instead of FH

  • Being aware of (at least) a dozen-or-two of most used modules is really helpful. For example, in the above code we never had to even mention the separator \.



回答2:

I can't write a full answer because I'm using my phone. In any case zdim has mostly answered you. But my solution would look like this

use strict;
use warnings 'all';
use feature 'say';

use File::Spec::Functions qw/ splitdir catdir /;

my $file = 'files.txt';

open my $fh, '<', $file or die qq{Unable to open "$file" for input: $!};

my @results;

while ( <$fh> ) {
    next unless /\S/;
    chomp;
    my @path = splitdir($_);
    shift @path while @path > 2;
    push @results, catdir @path;
}

print "$_\n" for @results;