有没有一种方法可以对bash中括号内的数字进行操作?
我有一个输入文件和一些行的格式- 此处任意文本{{x1 x2}{x3 x4}}此处任意文本 其中,x1、x2、x3和x4为浮点数和/或整数。有没有办法,比如说,通过使用awk/perl/bash脚本,将这些数字(总是用大括号括起来)翻一番 我尝试使用下面的变体,但我对awk是新手,甚至无法在花括号中分离出数字- awk-F(“{gsub({})”,“,$NF);打印$NF}” 范例- 输入: 任意文本1此处{{1 2}{3 4}}任意文本1此处 任意文本2此处{{2.0 4}{6.0 8}}任意文本2此处 这里是任意文本2P5 任意文本3此处{{36}{9 12}任意文本3此处 任意文本4此处{{4 8}{12 16}任意文本4此处 输出: 任意文本1此处{{2 4}{6 8}任意文本1此处 任意文本2此处{{4.0 8}{12.0 16}任意文本2此处 这里是任意文本2P5 任意文本3此处{{6 12}{18 24}任意文本3此处 任意文本4此处{{8 16}{24 32}任意文本4此处有没有一种方法可以对bash中括号内的数字进行操作?,bash,perl,unix,awk,Bash,Perl,Unix,Awk,我有一个输入文件和一些行的格式- 此处任意文本{{x1 x2}{x3 x4}}此处任意文本 其中,x1、x2、x3和x4为浮点数和/或整数。有没有办法,比如说,通过使用awk/perl/bash脚本,将这些数字(总是用大括号括起来)翻一番 我尝试使用下面的变体,但我对awk是新手,甚至无法在花括号中分离出数字- awk-F(“{gsub({})”,“,$NF);打印$NF}” 范例- 输入: 任意文本1此处{{1 2}{3 4}}任意文本1此处 任意文本2此处{{2.0 4}{6.0 8}}任意
下面是Ruby中的一个示例
$ echo "Arbitrary text here {{1.22 -3.55} {6.77 1e66}} arbitrary text here" |
ruby -lane 'p $_[/^[^{]*/] <<
$_[/{.*}/].gsub!(/[^ {}]+/) {|f| f.to_f*2} <<
$_[/[^}]*$/]'
"Arbitrary text here {{2.44 -7.1} {13.54 2.0e+66}} arbitrary text here"
这里的两种方法都是处理开头的{
和结尾的}
作为“查找浮点并用它做点什么”行为的开始。例如,没有对平衡大括号的解析。在这种情况下,如果是独立的,Perl和Ruby都会将非数字视为0.0
,如果是在一个数字串中,则将数字终止:
$ echo "Arbitrary text here {{1.22 -3.55 aa} {6s.77 1ye66}} arbitrary text here" |
perl -lane '$lh = $1 if m/(^[^{]*)/;
$rh = $1 if m/([^}]*)$/;
$tgt = $1 if m/(\{.*\})/;
$tgt =~ s/([^{} ]+)/$1*2/ge; # the "e" executes the sub as Perl code
print "$lh$tgt$rh\n";'
Arbitrary text here {{2.44 -7.1 0} {12 2}} arbitrary text here
这可能是也可能不是一个特征
随着您的更新。对整数也很有效:
$ echo "Arbitrary text1 here {{1 2} {3 4}} arbitrary text1 here
Arbitrary text2 here {{2 4} {6 8}} arbitrary text2 here
Arbitrary text2p5 here
Arbitrary text3 here {{3 6} {9 12}} arbitrary text3 here
Arbitrary text4 here {{4 8} {12 16}} arbitrary text4 here" |
perl -lane '$rh=$lh=$tgt="";
$lh = $1 if m/(^[^{]*)/;
$rh = $1 if m/([^}]*)$/;
$tgt = $1 if m/(\{.*\})/;
$tgt =~ s/([^{} ]+)/$1*2/ge; # the "e" executes the sub as Perl code
if ($rh && $lh && $tgt) {
print "$lh$tgt$rh" ;
} else {
print $_;
}'
Arbitrary text1 here {{2 4} {6 8}} arbitrary text1 here
Arbitrary text2 here {{4 8} {12 16}} arbitrary text2 here
Arbitrary text2p5 here
Arbitrary text3 here {{6 12} {18 24}} arbitrary text3 here
Arbitrary text4 here {{8 16} {24 32}} arbitrary text4 here
您可以捕获所需的模式,并使用它们的替换项重写字符串 这里有一个基本的方法:首先捕获组件,处理它们,然后重新组装
use warnings;
use strict;
my $str = 'Arbitrary text here {{1 2} {3 4}} arbitrary text here';
my @parts = $str =~ /(.*?){{(\d+) (\d+)} {(\d+) (\d+)}}(.*)/;
# If we expect only lines in the above format test and handle the error
if (@parts != 6) {
die "Didn't find expected patterns in: $str";
}
my $pre_text = shift @parts;
my $post_text = pop @parts;
my ($r1, $r2, $r3, $r4) = map { $_*2 } @parts;
my $result = $pre_text . "{{$r1 $r2}{$r3 $r4}}" . $post_text;
print $result, "\n";
代码假定输入的格式如图所示。这种“手动”分步方法的一个优点是更容易根据需要调整流程的每个部分
这可以在一个正则表达式中完成。由于盲目相信预期的数据格式通常是一个非常糟糕的主意,我们可以将替换代码放入子正则表达式中, 因此,可以根据需要更轻松地检查和处理匹配项
sub repl {
my @nums = @_;
die "Expected four numbers, got: @nums" if @nums != 4;
my ($r1, $r2, $r3, $r4) = map { $_ * 2 } @nums;
return "{{$r1 $r2} {$r3 $r4}}";
}
$str =~ s/{{(\d+) (\d+)} {(\d+) (\d+)}}/repl($1, $2, $3, $4)/e;
这也大大清理了正则表达式本身
如果模式不匹配,则不会发生任何事情,$str
保持不变。如果我们只希望使用此格式的行,则可能需要了解匹配失败的情况。了解此情况的一种方法是
if (not $str =~ s/.../) { warn "Failed match on: $str" }
因为替换运算符s/
返回所进行的替换的数目
更新提供的输入示例 上面的单个正则表达式方法,带有一个带有输入行的文件
input.txt
use warnings;
use strict;
my $file = 'input.txt';
open my $fh, '<', $file or die "Can't open $file: $!";
while (<$fh>) {
s/{{(\d+) (\d+)} {(\d+) (\d+)}}/repl($1, $2, $3, $4)/e;
print;
}
sub repl {
my @nums = @_;
die "Expected four numbers, got: @nums" if @nums != 4;
my ($r1, $r2, $r3, $r4) = map { $_ * 2 } @nums;
return "{{$r1 $r2} {$r3 $r4}}";
}
使用警告;
严格使用;
my$file='input.txt';
打开我的$fh,'你是否在寻找一些可以在花括号内找到数字的东西,这些数字可能是嵌套的,然后每个数字都翻倍?请你的问题显示一些示例输入和所需输出。是的,一般来说这是可能的,但如果没有具体的示例说明你想要实现什么,这不是一个任务这是一个很好的答案。谢谢,我添加了一个具体的例子。你的例子不是浮点数。那些是整数。
use warnings;
use strict;
my $file = 'input.txt';
open my $fh, '<', $file or die "Can't open $file: $!";
while (<$fh>) {
s/{{(\d+) (\d+)} {(\d+) (\d+)}}/repl($1, $2, $3, $4)/e;
print;
}
sub repl {
my @nums = @_;
die "Expected four numbers, got: @nums" if @nums != 4;
my ($r1, $r2, $r3, $r4) = map { $_ * 2 } @nums;
return "{{$r1 $r2} {$r3 $r4}}";
}
Arbitrary text1 here {{2 4} {6 8}} arbitrary text1 here
Arbitrary text2 here {{4 8} {12 16}} arbitrary text2 here
Arbitrary text2p5 here
Arbitrary text3 here {{6 12} {18 24}} arbitrary text3 here
Arbitrary text4 here {{8 16} {24 32}} arbitrary text4 here