How to use $string=~s/(whatever)/${$i}/; with strict ref?

Y

yjnnhauhht

Hi,

The following works without strict ref (withh perl 5.10 not 5.8) :
my $i=1;
my $string="teststring";
$string=~s/(test)/${$i}/;
print "$string\n";

But fails to compile with error message "Can't use string ("1") as a
SCALAR ref while "strict refs"" with strict ref.

Is there a way to write it differently so that it's accepted with
strict ref?

Regards,
Yjnnhauhht.
 
P

Peter Makholm

yjnnhauhht said:
But fails to compile with error message "Can't use string ("1") as a
SCALAR ref while "strict refs"" with strict ref.

Is there a way to write it differently so that it's accepted with
strict ref?

No, but you can disable strict refs in a block:

#!/usr/bin/perl

use strict;
use warnings;

use 5.10.0;

my $i = 1;
my $string = "teststring";

{
no strict 'refs';

$string =~ s/(test)/\U${$i}/i;
}

say $string;

$string =~ s/(test)/\L${$i}/i;

say $string;
__END__

//Makholm
 
S

sln

Hi,

The following works without strict ref (withh perl 5.10 not 5.8) :
my $i=1;
my $string="teststring";
$string=~s/(test)/${$i}/;
print "$string\n";

But fails to compile with error message "Can't use string ("1") as a
SCALAR ref while "strict refs"" with strict ref.

Is there a way to write it differently so that it's accepted with
strict ref?

${$ .. is dereferencing notation so $i must be a reference.
If you change it to $i = \2, it would then be a reference and you wouldn't get
that message.
Then $string would contain "1string" after the substitution.

But, I get the feeling you want to have a variable capture buffer variable.
In that case the replacement side should be done seperately as an actual variable
assignment "string".

Or you can combine it all in a double eval regex as something like this:
(expanded with print for detail)

$i = 2;
$string =~ s/(test)(string)/print '${'.$i."}\n"; '${'.$i.'}'/ee;
# or, shortened
# $string =~ s/(test)(string)/'$'.$i/ee;


-sln
 
S

sln

Or you can combine it all in a double eval regex as something like this:
(expanded with print for detail)

$i = 2;
$string =~ s/(test)(string)/print '${'.$i."}\n"; '${'.$i.'}'/ee;
# or, shortened
# $string =~ s/(test)(string)/'$'.$i/ee;

Or, another popular notation:

$string =~ s/(test)(string)/"\$$i"/ee;

-sln
 
S

sln

Is it, by chance:

my $i=1;
my $string="teststring";
$string=~s/(?<test>test)/$+{test}/;
print "$string\n";

?

This is equivalent to the trivial solution as there is no need
for $i. In that case s/test/test/ is faster.

-sln
 
Y

yjnnhauhht

Is it, by chance:

my $i=1;
my $string="teststring";
$string=~s/(?<test>test)/$+{test}/;
print "$string\n";

?

This doesn't solve my issue, cause I need to do the thing in a for
loop where the $i is incremented.
Thanks for your time though.
 
Y

yjnnhauhht

This doesn't solve my issue, cause I need to do the thing in a for
loop where the $i is incremented.
Thanks for your time though.

Well what I really want to do is some kind of "highlighting grep -E"
which highlights the part of the match pattern that is inside ().
For example if I do mygrep "...\w*(test)..." file, I get the lines
matching the pattern and the word test is highlighted.
To do this I have to add a highligth/nohighligth control string before
and after each () group.
I though I will be able to do this in one regex, but failed and only
found a solution where I need to iterate on the () groups and do the
s/.../$i/ I ask you about.
 
C

C.DeRykus

Well what I really want to do is some kind of "highlighting grep -E"
which highlights the part of the match pattern that is inside ().
For example if I do mygrep "...\w*(test)..." file, I get the lines
matching the pattern and the word test is highlighted.
To do this I have to add a highligth/nohighligth control string before
and after each () group.
I though I will be able to do this in one regex, but failed and only
found a solution where I need to iterate on the () groups and do the
s/.../$i/ I ask you about.

my $str = "1a:23b:4c";

$str = s{ (\d+)(\w+) }
{ my $s;$s .= qq{[$_]} for $1,$2;$s }gex;
 
S

sln

Quoth yjnnhauhht said:
Well what I really want to do is some kind of "highlighting grep -E"
which highlights the part of the match pattern that is inside ().
For example if I do mygrep "...\w*(test)..." file, I get the lines
matching the pattern and the word test is highlighted.
To do this I have to add a highligth/nohighligth control string before
and after each () group.
I though I will be able to do this in one regex, but failed and only
found a solution where I need to iterate on the () groups and do the
s/.../$i/ I ask you about.

Well, now that you've *said* so...

my $str = "1a:23b:4c";

while ($str =~ /(\d+)(\w+)/g) {
my $added = 0;
for (1..$#+) {
substr $str, $-[$_] + $added, 0, "[";
$added++;
substr $str, $+[$_] + $added, 0, "]";
$added++;
}
pos($str) = $+[-1] + $added;
}

Ben

This approach is too simple. It won't handle nested groups;
/((\d+)(\w+))/ for example.

Then again, a more complex method that handles nesting
runs up against the indeterminate configuration;
'asdf' =~ /((X?))asdf/
'asdf' =~ /(X?)(Y?)asdf/
prodcing:
@- 0 0 0 0
@+ 4 0 0 4
The solution is to exclude empty capture groups.

I'd be curious if anyone else knows a simpler workable method other
than the below code (that works on nested groups).

-sln

---------------------------
use strict;
use warnings;

#
# This works for nested groups (but too complex)
#
my $str = "1aw23b:4c";

while ($str =~ /(\d+)[a-z]*(([a-z]):)?))/g)
{
my $newpos = pos($str);
my @B = @-;
my @E = @+;
my $numgrps = $#B;

for my $grp (1 .. $numgrps)
{
next if ($B[$grp] == $E[$grp]);
my $i;
##
my $curBpos = $B[$grp];
substr $str, $curBpos, 0, '[';
for $i ($grp .. $numgrps) {
++$B[$i] if ( $B[$i] >= $curBpos );
}
for $i ($grp .. $numgrps) {
++$E[$i] if ( $E[$i] >= $curBpos );
}
##
my $curEpos = $E[$grp];
substr $str, $curEpos, 0, ']';
for $i ($grp .. $numgrps) {
++$B[$i] if ( $B[$i] >= $curEpos );
}
for $i ($grp .. $numgrps) {
++$E[$i] if ( $E[$i] >= $curEpos );
}
$newpos += 2;
}
pos($str) = $newpos;
}

print $str,"\n";

#
# This does NOT work for nested groups (too simple)
#
$str = "1aw23b:4c";

while ($str =~ /(\d+)[a-z]*(([a-z]):)?))/g) {
my $added = 0;
for (1..$#+) {
next if ($-[$_] == $+[$_]);
substr $str, $-[$_] + $added, 0, "[";
$added++;
substr $str, $+[$_] + $added, 0, "]";
$added++;
}
pos($str) = $+[-1] + $added;
}
print $str,"\n";

__END__


[1]a[[w]][23][[:]][4][[c]]
[1]a[w[]][23][b[:][]][4][c[]]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top