Procura e substitui usando um utilitário personalizado

1

Eu quero executar um utilitário para substituir valores correspondentes a uma expressão regular. Isso significa que para cada correspondência de uma expressão regular, chame o utilitário com os caracteres que compõem a correspondência. A saída do utilitário substitui os caracteres originais.

Para fins de ilustração usando factor :

$ factor 230
230: 2 5 23

Portanto, usando esse utilitário, quero selecionar os inteiros, chamar factor com o inteiro e substituir o inteiro original pela saída de factor .

Isso é o que eu esperaria de uma entrada de exemplo:

$ [code] <<< "Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes."
Given the numbers with factors: 27: 3 3 3, 13: 13, 230: 2 5 23, and 19: 19, it is evident which are primes.

Eu pensei que isso poderia funcionar, mas parece que está tentando interpretar a entrada diretamente. Usando sed (GNU sed) 4.2.2 .

$ sed -E 's/([0-9]+)/factor /ge' <<< 'Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes.'
sh: 1: Given: not found

Obviamente, não estou entendendo o que o e flag faz. Remover o e mostra que a expressão regular está puxando corretamente os inteiros e passando-os como .

Eu tentei fazer isso em awk :

$ awk '{r = gensub(/([0-9]+)/, system("factor \1"), "g"); print r}' <<< 'Given the numbers with factors: 27, 13, 230, and 19, it is evident which are primes.'
1:
Given the numbers with factors: 0, 0, 0, and 0, it is evident which are primes.

Não sei de onde vem o 1: , mas é evidente que está imprimindo apenas o código de retorno de system . Não parece haver uma maneira de capturar a saída padrão de um comando em awk .

O que eu estou pedindo é possível usando os principais utilitários?

    
por Yimin Rong 18.07.2018 / 15:16

4 respostas

1

Possível em Perl. Usando divisão , mapa , scalar , lc , inverter , ucfirst , aderir . Um pouco mais complexo do que eu pensava originalmente por causa das vírgulas e da sensibilidade do contexto de correspondência.

#!/usr/bin/perl
use warnings;
use strict;

sub rev {
    my ($string) = @_;
    my @words = split /(\W+)/, $string;
    my @caps = map scalar(/^[[:upper:]]/), @words;
    $_ = /\w/ ? lc reverse : $_ for @words;
    shift @caps and $_ = ucfirst for @words;
    return join "", @words
}

use Test::More tests => 1;
my $r = rev('Hello, my name is Yimin Rong.');
is $r, 'Olleh, ym eman si Nimiy Gnor.';
    
por 18.07.2018 / 15:31
0

Experimente a solução awk abaixo:

echo "Hello" | awk '{ for ( i=length($0);i>0;i-- ) { if (i == length($0) ) { printf "%s",toupper(substr($0,i,1)) } else {  printf "%s",tolower(substr($0,i,1)) } } printf "\n" }'

Pegue cada letra da palavra caractere por caractere, indicando a última. Se for o último caractere, converta para maiúscula e imprima, caso contrário imprima minúsculas.

    
por 18.07.2018 / 15:57
0

Execute o seguinte:

 perl -pe 's/(\d+)/qx(factor $1) =~ s|\n||r/ge'  input-file.txt

A razão pela qual seu comando sed não está funcionando é porque sed executará todo o espaço de padrões diferente de Perl, que está alinhado com o modo como você estava pensando e executa tanto quanto no comando s /// e substitui muito com a saída do comando.

E é exatamente por isso que, se você perceber que o sed estava abrindo o utilitário "Given:" não encontrado. Dado foi o começo do seu espaço padrão. HTH

    
por 20.07.2018 / 20:09
-1

Execute o seguinte:

perl -pe 's/(\d+)/qx(factor $1) =~ s|\n||r/ge'  input-file.txt
    
por 20.07.2018 / 20:07