Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
Suppose you have the following variable:
>my_id ---------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +----------------------------
and a Hash of Arrays that has ranges of numbers in pairs :
123-186 188-259 263-340 1-93
What I want to do, is to substitute the - with A for every range that is mentioned in all the arrays of the HoA.
I have written this simple code so far:
my $id = '------------------------------------------------------------ +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +--------------------------------------------------------------------- +-------------------------------------- '; foreach my $l ( 0 .. $#{ $HoA{$id} } ) { my $separate_range = $HoA{$id}[$l]; if($separate_range=~/(\d+)\-(\d+)/) { my $hit_beg=$1; my $hit_end=$2; my $hit_length=$hit_end-$hit_beg+1; } }
How will I continue in order to substitute, e.g. all characters between position 123 and 186 from - to A?

Replies are listed 'Best First'.
Re: How do you perform this substitution?
by toolic (Bishop) on Jun 25, 2014 at 11:36 UTC
    substr
    use warnings; use strict; my $id = '-' x 50; print "$id\n"; while (<DATA>) { chomp; my ($s, $e) = split /\-/; my $copy = $id; my $len = $e - $s + 1; substr($copy, $s-1, $len) = 'A' x $len; print "$copy\n"; } __DATA__ 7-10 12-40

    Outputs:

    -------------------------------------------------- ------AAAA---------------------------------------- -----------AAAAAAAAAAAAAAAAAAAAAAAAAAAAA----------
Re: How do you perform this substitution?
by Laurent_R (Canon) on Jun 25, 2014 at 17:50 UTC
    Please also notice how toolic created the dash line, using the x operator. It is much handier than what you had.
Re: How do you perform this substitution?
by AnomalousMonk (Archbishop) on Jun 25, 2014 at 18:26 UTC

    Also, please note that the use of a 656 character example string for  $id is just a tad bit extreme!

Re: How do you perform this substitution?
by ww (Archbishop) on Jun 27, 2014 at 00:35 UTC

    NOT because this is useful, elegant, or even extensible code: hardcoded vars, sted calculated vars; RITW (and in this case, probably a five-wheeled q'cycle). But just because embedded newlines intrigue me...

    #!\usr/bin/perl use warnings; use strict; use 5.016; # 1091171 with modifications to handle strings w/embedded newlines my @data = <DATA>; my $source = ('-' x 50 . "\n" . '-' x 75); my @id = split /\n/, $source; my ($tag, $line, $id, $offset, $end, $substr_len, $len, $range); for $id(@id) { chomp $id; if ( $id =~ /^-{50}$/ ) { $len = length($id); $tag = "VAR1: "; for $range(@data) { ($offset, $end) = split /-/, $range; chomp $offset; chomp $end; my $substr_len = ($end - $offset + 1); if ($offset + $substr_len <= $len) { substr ($id[0], $offset - 1, $substr_len) = ('A' x + $substr_len); say "$tag: id[0]\n\tModified line: |$id[0]|\n"; } else { say "At Ln26: \$end: $end > \$len: $len"; say "Replacements attempted beyond end of string.\ +n\n"; next; } } $id = ''; } else { $tag = "VAR2: "; say "\n\t\t NOW WORKING ON $tag \n"; chomp $id[1]; my $len = length($id[1]); for $range(@data) { my ($offset, $end) = split /-/, $range; chomp $offset; chomp $end; my $substr_len = ($end - $offset + 1); if ($offset + $substr_len <= $len) { substr ($id[1], $offset - 1, $substr_len) = ('B' x + $substr_len); say "$tag: id[1]\n\tModified line: |$id[1]|\n"; } else { say "At Ln55: \$end: $end > \$len: $len"; say "Replacements attempted beyond end of string." +; } } } } =head OUTPUT C:\>1091171.pl VAR1: : id[0] Modified line: |------AAAA------------------------------------ +----| VAR1: : id[0] Modified line: |------AAAA-AAAAAAAAAAAAAAAAAAA---------------- +----| At Ln26: $end: 60 > $len: 50 Replacements attempted beyond end of string. NOW WORKING ON VAR2: VAR2: : id[1] Modified line: |------BBBB------------------------------------ +-----------------------------| VAR2: : id[1] Modified line: |------BBBB-BBBBBBBBBBBBBBBBBBB---------------- +-----------------------------| VAR2: : id[1] Modified line: |------BBBB-BBBBBBBBBBBBBBBBBBB----BBBBBBBBBBBB +BBBBBBBBBBBBBB---------------| C:\> =cut __DATA__ 7-10 12-30 35-60

    Come, let us reason together: Spirit of the Monastery

    ... but check Ln42!

Re: How do you perform this substitution?
by Anonymous Monk on Jun 25, 2014 at 11:26 UTC
    Ah, got I think, I will use substr.
Re: How do you perform this substitution?
by Anonymous Monk on Jun 25, 2014 at 12:06 UTC
    The documentation merely "assumes" that you know what the compiler-term lvalue means. What it means is what has been done here. Another useful technique is to use the optional fourth-argument of the substr() function to perform the substitution while returning what used to be there ... very handy if for any reason you need to know what it is you just substituted.
      Ah, also nice trick that you can do the substitution inside the substr command.
      Thanks again!