Como posso acrescentar uma contagem incremental a cada palavra predefinida de um arquivo de texto?

2

Como posso acrescentar uma contagem incremental a cada palavra predefinida de um arquivo de texto?

Assim como esta pergunta: Como posso acrescentar uma contagem incremental a cada linha de um arquivo de texto?

Eu quero adicionar uma contagem incremental a um arquivo de texto. Mas, em vez de adicionar uma contagem incremental a cada linha, gostaria de adicionar uma contagem incremental a uma palavra predefinida.

Por exemplo, se eu quiser contar a palavra 'cinema' no texto, gostaria que todas as ocorrências de 'cinema' fossem alteradas para 'cinemaN', onde N é o número incremental e o valor máximo de N é dependente quantas vezes a palavra "cinema" ocorre no texto.

Para que um arquivo de texto de entrada contenha este texto:

He drove his car to the cinema. He then went inside the cinema to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema.

Gera um arquivo de saída com este conteúdo:

He drove his car to the cinema1. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema3.

De preferência, eu também gostaria de poder numerar a palavra selecionada em ordem inversa.

Ou seja. isso geraria um segundo arquivo de saída com este conteúdo:

He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema1.

    
por sku2003 17.04.2017 / 12:14

4 respostas

1

Tendo em conta a pontuação após a palavra.
Numeração para a frente:

word="cinema"
awk -v word="$word" '
    { 
      for (i = 1; i <= NF; i++) 
        if ($i ~ word "([,.;:)]|$)") { 
          gsub(word, word "" ++count,$i) 
        }
      print 
    }' input-file

Numeração retroativa:

word="cinema"
count="$(awk -v word="$word" '
    { count += gsub(word, "") }
    END { print count }' input-file)"
awk -v word="$word" -v count="$count" '
    { 
      for (i = 1; i <= NF; i++) 
        if ($i ~ word "([,.;:)]|$)") { 
          gsub(word, word "" count--, $i) 
        }
      print 
    }' input-file
    
por 17.04.2017 / 13:00
3

Eu prefiro perl para isso:

$ cat ip.txt 
He drove his car to the cinema. He then went inside the cinema to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema.

$ # forward counting is easy
$ perl -pe 's/\bcinema\b/$&.++$i/ge' ip.txt 
He drove his car to the cinema1. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema3.
  • \bcinema\b palavra a procurar, usando limites de palavras para que não correspondam como parte parcial de outra palavra. Por exemplo, \bpar\b não corresponde a apart ou park ou spar
  • ge o g flag é para substituição global. e permite usar o código Perl na seção de substituição
  • $&.++$i é concatenação de palavra correspondente e valor pré-incrementado de $i , que possui valor padrão de 0


Por reverso, precisamos obter a contagem primeiro ...

$ c=$(grep -ow 'cinema' ip.txt | wc -l) perl -pe 's/\bcinema\b/$&.$ENV{c}--/ge' ip.txt 
He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema1.
  • c se torna variável de ambiente acessível através do hash %ENV

ou, com perl sozinhos, fazendo slurping no arquivo inteiro

perl -0777 -pe '$c=()=/\bcinema\b/g; s//$&.$c--/ge' ip.txt 
    
por 17.04.2017 / 14:34
2

Com o GNU awk para multi-char RS, correspondência insensível a maiúsculas e limites de palavras:

$ awk -v RS='^$' -v ORS= -v word='cinema' '
    BEGIN { IGNORECASE=1 }
    { cnt=gsub("\<"word"\>","&"); while (sub("\<"word"\>","&"cnt--)); print }
' file
He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema1.
    
por 18.04.2017 / 16:02
0

Para marcar a palavra em ordem decrescente, invertemos a regex E invertemos os dados e finalmente invertemos a data novamente para efetuar a transformação:

perl -l -0777pe '$_ = reverse reverse =~ s/(?=\bamenic\b)/++$a/gre' input.data

Resultado

He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and
afterwards discovered that it was more then two years since he last visited the cinema1.

Para marcar a palavra em ordem crescente, pesquisamos a palavra:

perl -lpe 's/\bcinema\b\K/++$a/eg' input.data

Resultado

He drove his car to the cinema1. He then went inside the cinema2 to purchase tickets, and
afterwards discovered that it was more then two years since he last visited the cinema3.
    
por 29.04.2017 / 16:46