Inline regex replacement in perl

不羁岁月 提交于 2019-12-12 09:36:19

问题


Is there a way to replace text with a regex inline, rather than taking the text from a variable and storing it in a variable?

I'm a perl beginner. I often find myself writing

my $foo = $bar;
$foo =~ s/regex/replacement/;
doStuff($foo)

where I'd really like to write

doStuff($bar->replace(s/regex/replacement/));

or the like, rather than using a temporary variable and three lines.

Is there a way to do this? Obviously when the regex is sufficiently complicated it makes sense to split it out so it can be better explained, but when it's just s/\s//g it feels wrong to clutter the code with additional variables.


回答1:


Starting from perl 5.14 you can use Non-destructive substitution to achieve desired behavior.

Use /r modifier to do so:

doStuff($bar=~s/regex/replacement/r);



回答2:


You really can't do what you want because the substitution function returns either a 1 if it worked or an empty string if it didn't work. That means if you did this:

doStuff($foo =~ s/regex/replacement/);

The doStuff function would be using either 1 or an empty string as a parameter. There is no reason why the substitution function couldn't return the resultant string instead of just a 1 if it worked. However, it was a design decision from the earliest days of Perl. Otherwise, what would happen with this?

$foo = "widget";
if ($foo =~ s/red/blue/) {
    print "We only sell blue stuff and not red stuff!\n";
}

The resulting string is still widget, but the substitution actually failed. However, if the substitution returned the resulting string and not an empty string, the if would still be true.

Then, consider this case:

$bar = "FOO!";
if ($bar =~ s/FOO!//) {
   print "Fixed up \'\$bar\'!\n";
}

$bar is now an empty string. If the substitution returned the result, it would return an empty string. Yet, the substitution actually succeeded and I want to my if to be true.

In most languages, the substitution function returns the resulting string, and you'd have to do something like this:

if ($bar != replace("$bar", "/FOO!//")) {
   print "Fixed up \'\$bar''!\n";
}

So, because of a Perl design decision (basically to better mimic awk syntax), there's no easy way to do what you want. However you could have done this:

($foo = $bar) =~ s/regex/replacement/;
doStuff($foo);

That would do an in place setting of $foo without first assigning it the value of $bar. $bar would remain unchanged.




回答3:


use Algorithm::Loops "Filter";

# leaves $foo unchanged
doStuff( Filter { s/this/that/ } $foo );



回答4:


You can use a do { } block to avoid creating a temporary variable in the current scope:

doStuff( do {(my $foo = $bar) =~ s/regex/replacement/; $foo} );



回答5:


Is this what you want?:

my $foo = 'Replace this with that';
(my $bar = $foo) =~ s/this/that/;
print "Foo: $foo\nBar: $bar\n";

Prints:

Foo: Replace this with that
Bar: Replace that with that



回答6:


There is yet another way: Write your own function:

sub replace (
    my $variable = shift;
    my $substring = shift;

    eval "\$variable =~ s${substring};";
    return $variable
}

doStuff(replace($foo, "/regex/replace/"));

This wouldn't be worth it for a single call, and it would probably just make your code more confusing in that case. However, if you're doing this a dozen or so times, it might make more sense to write your own function to do this.



来源:https://stackoverflow.com/questions/3330882/inline-regex-replacement-in-perl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!