tags:

views:

119

answers:

5

I want to replace a lines that ends with 'YES' with 'YES' and replace lines that ends with 'NO'with 'NO'. I have to apply for a large file.

Input:

 max. C    13       0.457   0.32   YES
 max. Y    13       0.232   0.33   NO
 max. S     1       0.315   0.87   NO  

Output:

YES
NO
NO
+1  A: 
perl -p -e 's/.*(YES|NO)\s*$/$1/;' 

If you want Y and N instead of YES and NO then change it to

s/.*(Y|N)[ESO]+$/$1/;

To read more about perl regular expressions, substitions, etc. check out "perldoc perlre" from the command line of your system where perl is installed

Paul
can v use the same logic in python???
bharathy
Yes, python also has regular expression substitution support. The code will be a little different but the regular expression between the slashes will be more or less the same.
Paul
Good answer, but your second regex `s/.*(Y|N)[ESO]+$/$1/` would also match "..... YO" and "....YEEEEEEEEESSSSEO", etc. ;-)`perl -p -e 's/.*(YES|NO)$/substr($1,0,1)/e;'` would be one way around that, but probably not the best...
FalseVinylShrub
@Paul: Wouldn't `s/.*(?:(Y)ES|(N)O)\s*$/$1$2/` work better for the Y/N capture?
Zano
Aha there's a bug! If you don't have YES or NO at the end of a line then the substitution fails and you get the full line back from -p. We can blame the data not matching the spec, but that's dysfunctional and actually Sinan's answer is more appropriate. @Zano I was going to blame this bug on you after testing your regexp, but discovered mine does it too because of the -p. Oh Well :-) I suppose the lesson here is match is probably a better methodology than substitution.
Paul
@Paul: that's no bug, the spec says how to replace certain lines - it doesn't say anything about non-matching lines, so they should be unchanged.
ysth
+2  A: 

Match in list context returns captured substrings:

#!/usr/bin/perl

use strict; use warnings;

while ( <DATA> ) {
    if (my ($resp) = /(YES|NO)\s+\z/) {
        print "$resp\n";
    }
}

__DATA__
 max. C    13       0.457   0.32   YES
 max. Y    13       0.232   0.33   NO
 max. S     1       0.315   0.87   NO

And, if you just wanted to capture the 'Y' or 'N', there are two options. One is to use two capture buffers and use grep to filer out the substring that did not match:

if (my ($resp) = grep defined, /(?:(Y)ES)|(?:(N)O)\s+\z/ ) {
    print "$resp\n";
}

or, better yet, use a named capture buffer:

if ( /(?: (?<resp>Y) ES) | (?: (?<resp>N) O) \s+\z/x ) {
    print "$+{resp}\n";
}

Output:

Y
N
N
Sinan Ünür
+1  A: 

This is upto you if you need it.

awk '{print $NF}' file_name
Vijay Sarathi
Ooh thats nice and short but he wanted perl. perl -p -e 'split(" ");' -e '$_ = pop @_ ;'This ought to be shorter but I'm having problems combining split and pop.
Paul
+3  A: 

Hi bharathy,
While Paul's answer is correct, I wanted to point out there was another way to look at your problem. Your question states that the line ends with "YES" or "NO". Therefore another thing you could do is split the line and print the last element, if it matches "YES" or "NO":

perl -lape'$_=$F[-1] if $F[-1]=~m/^(?:YES|NO)$/'

In your example, all the lines ended in YES or NO. If this is really the case for all lines in your input, this can be simplified to:

perl -lape'$_=$F[-1]'

A short explanation of the Perl command-line flags used (you can also read this at "perldoc perlrun"):

  • -l is used to automatically chomp the input strings and append "\n" when printing.
  • -a auto-splits the input line on whitespace into the @F array, when used together with "-n" or "-p".
  • -p creates a loop that runs over the lines of the given input file/s and does a "print" at the end after your code is run.
  • -e is of course the flag for giving code on the command line

So basically the command-line flags do most of the work. The only thing I have to do is assign $F[-1] (the last element of the line) into $_ which is the thing which will be printed thanks to "-p".

My goal wasn't to play Perl Golf and show you a shorter way of answering your question, instead I'm trying to point out that simply thinking about a problem from a slightly different angle can show you different ways to solve it, which might be better/more elegant. So please don't focus on which solution is shorter, instead think about how different people attacked even this simple problem from different directions and how you can do the same.

One more point, you wrote "I want to replace a lines". If you meant replace in the input file itself, the "-i" (in-place replace) command-line flag is your friend:

perl -lapi.bak -e'$_=$F[-1]'
Offer Kaye
cool. so that more or less does the same as split and pop.
Paul
+1  A: 

Dear Friend,

You can use the following code also,

use strict;
use warnings;
my $var;
open (FH,"<file") or die "$! can't open";
while($var=<FH>)
{
     chomp($var);
     $var=~s/.*(YES|NO)$/$1/;
     print "$var\n";
}

In this code I used the chomp function. This function is used to remove the "\n". After that I checked the end of the line contains "YES" or "NO"

muruga