I have a rather simple task in trying to extract keywords from input.dat which looks like:

        yes         true;
        keyword123  (1.1 0 -0.3);
        gamma       (0 1 0);
        dir         (1 0 0);
        yes         false;
        keyword123  (1.1 0 -0.3);
        gamma       (0 0 1);
        dir         (1 0 0);

In this case I want to get the first entry in the vector of keyword123. If the lines containing the keyword aren't identically, the script should stop with an error. I feel that this should be a one- or twoliner in PERL using RegEx but it took me some time to get the following script:

#!/usr/bin/perl -w

use strict;

my $path = "./input.dat";

# array @grepped of lines containing keyword
my @grepped=();
open(FILE,"$path") or die "error on opening $path: $!\n";
while (my $line = <FILE>) {
        if ($line=~ /keyword123/i){push(@grepped,"$line")};

# get array @unique of unique lines
my %seen;
my @unique = grep {!$seen{$_}++} @grepped;

# continue with $unique if keyword-line is unique
my $unique;
if (scalar @unique eq 1) {
} else {
        die "entry not unique, exiting: $!\n";

# get string between brackets
$unique =~ /\((.+?)\)/;
my $final = $1;

# cut after first space
$final =~ s/\s.*//s;
print "keyword123: $final\n";

The script is giving the correct output but this can't be the best work, so any help/hint would be highly appreciated.


This is how I would implement it:

use warnings;
use strict;    

my $file = 'input.dat';
open my $IN, '<', $file or die $!;

my $uniq;
while (my $line = <$IN>) {
    next unless $line =~ /^\s*keyword123/;
    if (defined $uniq and $line ne $uniq) {
        die "Entry not unique. Exiting.\n";
    $uniq = $line;
$uniq =~ s/.*\((.*)\).*/$1/;
$uniq =~ s/\s.*//;
print "keyword123: $uniq";

You can check the uniqueness each time you read the keyword line in. Once you find a non-unique line, you can stop right at the moment, no need to search the rest of the file.

| improve this answer | |

I beat it down to this (below). Since you didn't do anything with the other information you accumulated, I chose the early-out strategy.

my $k123;
open( my $fh, '<', './input.dat' ) or die "error on opening $path: $!\n";
while ( my $l = <$fh> ) {
    chomp $l;
    next unless $l =~ m/keyword123/i;
    $k123 //= $l;
    die "Entry not unique!" unless $k123 eq $l;
close $fh;
say "keyword123: ", ( $k123 =~ /\(([^)]+)\)/ );
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.