[英]How to search and modify floating values that follow a string in a file using Perl
假設我們在一個文件中多次出現“abc {{1.1 2.2}}”,我想將其修改為“xyz {{2.2 4.4}}”,這基本上是:
abc {{1.1 2.2}} ----------> xyz {{2.2 4.4}}
必須對文件的所有實例進行此修改。 這是我嘗試過的代碼,但只能將 abc 替換為 xyz 並且無法弄清楚如何通過提取這些浮點值來進行操作。
#!/usr/bin/perl -w
use strict;
open(FILE, "</tmp/yourfile.txt") || die "File not found";
my @lines = <FILE>;
close(FILE);
foreach(@lines) {
$_ =~ s/abc/xyz/g;
}
open(FILE, ">/tmp/yourfile.txt") || die "File not found";
print FILE @lines;
close(FILE);
任何形式的幫助都受到高度贊賞。
我認為您希望保留小數位數(和/或控制它),並且可能需要以比單純*2
更復雜的方式來操作浮點數
perl -wE' $_=q(abc {{0.2 14.55}});
say;
s{ abc \s+ \{\s*\{\s* \K
([0-9]+\.([0-9]+)) (\s+) ([0-9]+\.([0-9]+)) (?=\s*\}\s*\})
}{
($l2,$l5) = map length, $2, $5;
sprintf("%.${l2}f", 2*$1) .$3. sprintf("%.${l5}f", 2*$4)
}ex;
say'
這提出了一些基本假設。 它打印
abc {{0.2 14.55}} abc {{0.4 29.10}}
注釋
\\K
使它放棄所有匹配到該點; 它們不需要被捕獲並重新輸入作為替代品,因為它們沒有被“消耗”。 所以我們匹配第一部分並不管它
}e
修飾符使其將替換端評估為 Perl 代碼。 在那里我們格式化乘以原始小數位數所得的數字
匹配部分末尾的位(?=...)
是前瞻
如果數字可能帶有-/+
則需要將這些字符添加到模式中
([-+]?[0-9]+\\.([0-9]+))
如果該+
需要在輸出中重現,那么您還需要捕獲符號([-+]?)
,以便能夠檢查替換側並添加它(如果它在那里)。
OP 未提供輸入文件樣本,因此以下代碼可能無法反映正確的解決方案。
假設模式abc {{xx xx}}
不會在行上出現多次。
use strict;
use warnings;
use feature 'say';
my $debug = 0;
for (<DATA>) {
chomp;
say $_ if $debug;
if( /(.*)?abc\s*\{\{\s*([\d\.]+)\s*([\d\.]+)\s*\}\}(.*)/ ) {
my($a,$b) = ($2,$3);
$a *= 2;
$b *= 2;
say $1 . "xyz {{$a $b}}" . $4;
} else {
say $_;
}
}
__DATA__
This an example data abc {{1.1 2.2}} which required some manipulation.
We should take abc {{1.1 2.2}} and replace 'abc' to 'xyz' take two
float numbers in curly brackets and multiply each by 2, write result
as xyz {{2.2 4.4}}.
Let's play with some numbers
abc {{7.2 12.4}}
boy {{0.5 8.2}}
put {{2.3 8.6}}
got {{4.1 2.3}}
abc {{0.5 4.9}}
Note: numbers can have values different from provided sample
輸出
This an example data xyz {{2.2 4.4}} which required some manipulation.
We should take xyz {{2.2 4.4}} and replace 'abc' to 'xyz' take two
float numbers in curly brackets and multiply each by 2, write result
as xyz {{2.2 4.4}}.
Let's play with some numbers
xyz {{14.4 24.8}}
boy {{0.5 8.2}}
put {{2.3 8.6}}
got {{4.1 2.3}}
xyz {{1 9.8}}
Note: numbers can have values different from provided sample
我的 Perl 正則表達式生銹了,但這樣的事情應該會有所幫助:
use Test::More tests => 6;
sub match_and_replace
{
$_[0] =~ /abc \{\{([+-]?([0-9]*[.])?[0-9]+) ([+-]?([0-9]*[.])?[0-9]+)}}/;
my $my1 = $1*2;
my $my3 = $3*2;
my $ret = $_[0];
$ret =~ s/abc \{\{$1 $3}}/xyz \{\{$my1 $my3}}/g;
return $ret;
}
is(match_and_replace('abc {{1.1 2.2}}'), 'xyz {{2.2 4.4}}', 'simple float');
is(match_and_replace('abc {{12.12 23.23}}'), 'xyz {{24.24 46.46}}', 'bigger float');
is(match_and_replace('abc {{1.99 99.1}}'), 'xyz {{3.98 198.2}}', 'another float');
is(match_and_replace('abc {{.5 .5}}'), 'xyz {{1 1}}', 'only fractional part');
is(match_and_replace('abc {{2 6}}'), 'xyz {{4 12}}', 'only integer part');
is(match_and_replace('abc'), 'abc', 'no match');
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.