user2593618
user2593618

Reputation: 21

Extract word before the 1st occurrence of a special string

I have an array that contains elements like

@array=("link_dm &&& drv_ena&&&1",
        "txp_n_los|rx_n_lost",
        "eof &&& 2 &&& length =!!!drv!!!0");

I want to get all the characters before the first "&&&", and if the element doesn't have a "&&&", then I need to extract the entire element.

This is what I want to extract:

likn_dm
txp_n_los|rx_n_lost
eof

I used

    foreach my $row (@array){
      if($row =~ /^(.*)\&{3}/){
        push @firstelements,$1;
      }
    }

But I'm getting

link_dm &&& drv_ena
txp_n_los|rx_n_lost
eof &&& 2

Can somebody please suggest how I can achieve this?

Upvotes: 2

Views: 65

Answers (4)

shawnhcorey
shawnhcorey

Reputation: 3601

If you're using regular expressions, use the minimum spanning pattern: .*?. See perldoc perlre http://perldoc.perl.org/perlre.html

#!/usr/bin/env perl

use strict;
use warnings;

# --------------------------------------

use charnames qw( :full :short   );
use English   qw( -no_match_vars );  # Avoids regex performance penalty

use Data::Dumper;

# Make Data::Dumper pretty
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Indent   = 1;

# Set maximum depth for Data::Dumper, zero means unlimited
local $Data::Dumper::Maxdepth = 0;

# conditional compile DEBUGging statements
# See http://lookatperl.blogspot.ca/2013/07/a-look-at-conditional-compiling-of.html
use constant DEBUG => $ENV{DEBUG};

# --------------------------------------

my @array = (
    "link_dm &&& drv_ena&&&1",
    "txp_n_los|rx_n_lost",
    "eof &&& 2 &&& length =!!!drv!!!0",
);

my @first_elements = ();
for my $line ( @array ){

  # check for '&&&'
  if( my ( $first_element ) = $line =~ m{ \A (.*?) \s* \&{3} }msx ){
    push @first_elements, $first_element;
  }else{
    push @first_elements, $line;
  }
}
print Dumper \@first_elements;

Upvotes: 0

perreal
perreal

Reputation: 97918

for (@array) {
    print "$1\n" if /([^ ]*)(?: *[&]{3}.*)?$/;
}

Upvotes: 0

Kenosis
Kenosis

Reputation: 6204

Perhaps just splitting would be helpful:

use strict;
use warnings;

my @array = (
    "link_dm &&& drv_ena&&&1",
    "txp_n_los|rx_n_lost",
    "eof &&& 2 &&& length =!!!drv!!!0"
);


foreach my $row (@array){
    my ($chars) = split /\&{3}/, $row, 2;
    print $chars, "\n"
}

Output:

link_dm 
txp_n_los|rx_n_lost
eof 

Upvotes: 3

ruakh
ruakh

Reputation: 183241

You can write:

@firstelements = map { m/^(.*?) *&&&/ ? $1 : $_ } @array;

Or, if you prefer foreach over map and if over ?::

foreach my $row (@array){
  if($row =~ /^(.*)\&{3}/) {
    push @firstelements, $1;
  } else {
    push @firstelements, $row;
  }
}

Upvotes: 0

Related Questions