Reputation: 157
I'm trying to write a perl script to search through a text file, find all decimal numbers, and modify them by some scaling factor. So far, I have succeeded in extracting the numbers with regular expressions:
open(INPUT, $inputPath) or die "$inputPath cannot be opened.";
while ($thisLine = <INPUT>) {
while ($thisLine =~ m/(-*\d+\.\d+)/g) {
if(defined($1)) {
$new = $scalingFactor*$1;
print $new."\n";
}
}
}
close (INPUT);
However, I haven't yet figured out how to reinsert the new values into the file. I tried using s/(-*\d+.\d+)/$scalingFactor*$1/g
for substitution, but of course this inserted the string representation of $scalingFactor
instead of evaluating the expression.
I'm a perl newbie, so any help would be greatly appreciated. Thanks in advance,
-Dan
Edit: Solution (based on Roman's Reply)
while ($thisLine = <INPUT>) {
$thisLine =~ s/(-*\d+\.\d+)/$scalingFactor*$1/ge;
prinf OUTPUT $thisLine;
}
Alternatively, Sean's solution also worked great for me. Thanks all!
Upvotes: 3
Views: 1869
Reputation: 29772
Here's a self-contained subroutine that'll do the job. It uses the special variable $^I
, which activates Perl's in-place editing feature. (See the "perlvar" man page for more information on $^I
, and the "perlrun" man page for information about the -i
command-line switch, which turns on in-place editing.)
use strict; # Always.
sub scale_numbers_in_file_by_factor {
my ($path, $scaling_factor) = @_;
local @ARGV = ($path);
local $^I = '.bak';
while (<>) {
s/ ( -? \d+ \. \d+ ) / $scaling_factor * $1 /gex;
print;
}
}
scale_numbers_in_file_by_factor('my-file.txt', .1);
A backup file will be made by appending '.bak'
to the original filename. Change the '.bak'
to ''
above if you don't want a backup.
You might want to tweak your number-recognizing regular expression. As written, it will not match numbers without a trailing decimal point and at least one digit. I think you also want -?
to match an optional minus sign, not -*
, which will match any number of minus signs. Performing arithmetic on a string with more than one leading minus sign will almost certainly not do what you want.
Upvotes: 4