简体   繁体   中英

PERL: how to search/replace elegantly beyond carriage return?

I had trouble googling this, as most people seem to want to know how to remove a carriage return.

The code I have works, but it seems awkward, and I'm missing something. It may be that my original script is designed poorly (I'm checking if one element occurs last, and if so, I need to change it,) but still...it seems I'm missing a quick way to make things smoother.

use strict;
use warnings;

my $a = "This is a string that I concatenate beforehand with carriage returns, so it's hard to separate out.\nThis is the last line I want to track.\nI want to delete this line.";
my $b = $a;

$b =~ s/(track\.).*/$1/g;

print "THIRD LINE STILL THERE\n$b\n\n";

my @c = split(/\n/, $a);
for (0..$#c) { 
   if ($c[$_] =~ /last line/) { 
      $b = join("\n", @c[0..$_]); 
      last; 
   } 
}

print "THIRD LINE GONE. IT WORKS, BUT I THINK THERE MUST BE A BETTER WAY.\n$b\n";

You have a good approach in your code, needing just a little more -- there's no need to iterate.

This removes the last line from a multi-line string.

my @lines = split '\n', $line;
pop @lines;
my $text = join '\n', @lines;

The pop removes the last element from the array. Or, if you wish to keep @lines whole

my @lines = split '\n', $line;
my $text = join '\n', @lines[0..$#lines-1];

Note that if the "last" line of text itself ends with a newline (so, if it is followed by an empty line), split nicely won't return an extra element, since it discards all trailing empty fields in the list that it then returns. So the code above remains the same.


Please note comments by Jonathan Leffler and Alan Moore . From the latter

"Newline" is a generic term for anything that's used to separate lines, including linefeed ( \\n ), carriage return( \\r ), a carriage return-linefeed pair ( \\r\\n ), and a few other, more exotic characters.

If you were to look for the " carriage return ", per title, or for other forms of "newline," you'd need to adjust the \\n in split and join above. See, for example, their Representations on Wikipedia .

这应该工作:

$b =~ s/track\..*/track\./sg;

You can use rindex(), which gets the last index of a position in a string, and combine that with substr(). like this:

$b = substr($a, 0, rindex($a, "\\n"));

If you want to keep the new line character at the end of your string, then do this:

$b = substr($a, 0, rindex($a, "\\n") + 1);
my $string = $a;
$string =~ s/I want to delete[^\n]*\n//gs;

There is nothing wrong with splitting the array and iterating over it. If you wanted to do it in one regex, you can also accomplish it by looking for the target string.

An additional note is to also avoid using $a and $b as they're often used as internal variables.

If I understood your question correctly, it seems what you need is pop :

use strict;
use warnings;

my $a = "This is a string that I concatenate beforehand with carriage returns, so it's hard to separate out.\nThis is the last line I want to track.\nI want to delete this line.";

my @lines     = split(/\n/, $a);
my $last_line = pop @lines;

print join('\n', @lines) . "\n"; # first two lines
print $last_line . "\n"; # in case you still want to use it ;)

Hope this helped

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM