user2837862
user2837862

Reputation: 51

perl: changing between line by line and as a whole

I'm starting to work with perl and I need to edit some text. Sometimes I need that perl read the input line by line and sometimes I need perl read the input as a whole. I know that this can be set with something like:

$/ = undef;

or with something like:

{
        local $/;
        $myfile= <$MYFILE>;
}

But Im not sure how I have to do if, in the same script, I want to change the reading from "whole" to "line by line" or viceversa. That is, imagine a script with starts as:

use warnings;
use strict;
my $filename = shift;
open F, $filename or die "Usa: $0 FILENAME\n";
while(<F>) {
}

And I make some replaces (s///;). And then I need that go on with my edition but reading as a whole. So I write:

{
        local $/;
        $filename = <F>;
}

But then I need to go on reading line by line....

Somebody can explain me the logic behind this in order to learn how to 'change' from one mode to another, always keeping the last edited version of the input? Thanks


Ok, sorry. I will try to focus on Y instead of X. For instance, I need to edit a text and make a replacement only on a portion of the text which is delimited by two words. So imagine I want to replace all the forms of "dog" to "cat", but only on those "dogs" which are bewtween the word "hello". My input:

hello
dog
dog
dog
hello
dog
dog

My output:

hello
cat
cat
cat
hello
dog

My script:

use warnings;
use strict;
my $file = shift;
open my $FILE, $file or die "Usa: $0 FILENAME\n";
{       
local $/;
$file = <$FILE>;
do {$file =~ s{dog}{cat}g} until
($file =~ m/hello/);
}
print $file;

But I get replaced all "dogs"

I tried other stratagey:

use warnings;
use strict;
my $file = shift;
open my $FILE, $file or die "Usa: $0 FILENAME\n";
{       
local $/;
$file = <$FILE>;
while ($file =~ m{hello(.*?)hello}sg) {
my $text = $1;
$text =~ s{dog}{cat}g;
}
}
print $file;

But in this case I get no replacement...

Upvotes: 1

Views: 76

Answers (2)

ThisSuitIsBlackNot
ThisSuitIsBlackNot

Reputation: 24063

You don't have to resort to slurping and multi-line regexes to solve this. Simply use a variable to track the state of the current line, i.e. whether you're inside or outside your delimiters:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

my $in_hello;
while (<DATA>) {
    chomp;
    $in_hello = ! $in_hello if $_ eq 'hello';
    s/dog/cat/ if $in_hello;
    say;
}

__DATA__
hello
dog
dog
dog
hello
dog
dog

Output:

hello
cat
cat
cat
hello
dog
dog

Upvotes: 2

mpapec
mpapec

Reputation: 50647

Default, line by line, mode is back again outside code block:

{
    local $/;
    $filename = <F>;
}

$/ is global variable which is dynamically scoped in this example.

Upvotes: 1

Related Questions