Как искать и изменять плавающие значения, следующие за строкой в ​​файле, используя Perl - PullRequest
1 голос
/ 17 февраля 2020

Допустим, у нас есть "ab c {{1.1 2.2}}", встречающийся несколько раз в файле, и я хочу изменить его на "xyz {{2.2 4.4}}", который в основном:

  • Измените ab c на xyz.
  • И умножьте плавающие значения на 2, которые появляются в фигурных скобках (всегда перед ключевым словом ab c).
abc {{1.1 2.2}} ----------> xyz {{2.2 4.4}}

Это изменение должно быть сделано для всех экземпляров файла. Вот код, который я попробовал, но смог заменить только ab c на 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);

Любая помощь очень полезна оценили.

Ответы [ 3 ]

3 голосов
/ 17 февраля 2020

Я предполагаю, что вы захотите сохранить количество десятичных знаков (и / или контролировать его), и что, возможно, нужно управлять поплавками способами, более сложными, чем простое *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'

Это делает некоторые базовые c предположения. Он печатает

abc {{0.2 14.55}}
abc {{0.4 29.10}}

Комментарии

  • \K позволяет отбрасывать все совпадения до этой точки; они не должны быть захвачены и повторно введены как замена, поскольку они не были "потреблены". Таким образом, мы сопоставляем эту первую часть и оставляем ее в покое

  • Модификатор }e позволяет ему оценить сторону замены как Perl код. Там мы форматируем числа, полученные в результате умножения, на число десятичных разрядов оригиналов

  • Бит в конце совпадающей части, (?=...), представляет собой lookahead

  • Если числа могут идти с -/+, то эти символы необходимо добавить к шаблону

    ([-+]?[0-9]+\.([0-9]+))
    

    Если это + необходимо воспроизвести в выходных данных как тогда вам также нужно захватить знак ([-+]?), чтобы иметь возможность проверить сторону замены и добавить ее (если она там была).

1 голос
/ 17 февраля 2020

Образец входного файла не был предоставлен OP, и по этой причине следующий код может не отражать правильное решение.

Предполагалось, что шаблон abc {{x.x x.x}} не будет представлен более одного раза в строке.

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
0 голосов
/ 17 февраля 2020

Мои 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');
...