Problema de pontuação usando o grep para obter n palavras ao redor do token

2

Estou tentando processar um arquivo. Minha tentativa não funcionou. O arquivo de entrada descreve a saída desejada:

Arquivo de entrada:

This is a token, but when any punctuation is encountered, it stops the extraction.

I want to get n words around a specific token, meaning n words before the token and n words after the token. There is no fix pattern, as given in some other solutions.

Please help. Thank you.

Comando usado:

$ grep -io -E  '(\w+ ){0,5}\b(token)\b( \w+){0,5}' grepping-n-words-around-token 

Saída:

This is a token
n words around a specific token
meaning n words before the token and n words after the
token

Saída desejada:

This is a token, but when any punctuation is
n words around a specific token, meaning n words before the
meaning n words before the token and n words after the
and n words after the token. There is no fix pattern
    
por user8616916 05.10.2017 / 20:12

1 resposta

3

Você não pode ter o GNU grep -o com o mesmo texto (como meaning n words before the ou and n words after the ) duas vezes. Você poderia fazer isso com pcregrep usando -o<n> , em que n é o grupo de captura n th e capturar o que é correspondido em um operador look ahead (que não avança o cursor para o próximo jogo):

$ pcregrep -o0 -o2  '(\w+\W+){0,5}token(?=((\W+\w+){0,5}))' file
This is a token, but when any punctuation is
n words around a specific token, meaning n words before the
meaning n words before the token and n words after the
and n words after the token. There is no fix pattern

-o0 corresponde a todo o texto, -o1 corresponde ao (....) no operador (?=(here)) look-ahead.

Observe que em uma entrada como:

6 5 4 3 2 1 token token 1 2 3 4 5 6

daria:

5 4 3 2 1 token token 1 2 3 4
token 1 2 3 4 5

porque começa a procurar a segunda correspondência logo após o primeiro token , portanto, encontra apenas 0 palavras antes da segunda token .

$ echo 6 5 4 3 2 1 token token 1 2 3 4 5 6 |
   pcregrep -o1  '(?=((\w+\W+){0,5}token(\W+\w+){0,5}))\w*'
5 4 3 2 1 token token 1 2 3 4
4 3 2 1 token token 1 2 3 4 5
3 2 1 token token 1 2 3 4 5
2 1 token token 1 2 3 4 5
1 token token 1 2 3 4 5
token token 1 2 3 4 5
token 1 2 3 4 5

Provavelmente não seria o que você deseja (mesmo que cada um seja "token" precedido e seguido por até cinco palavras).

Para obter uma linha para cada ocorrência de "token" com até cinco palavras em ambos os lados, não acho que você faça isso facilmente com pcregrep sozinho.

Você precisaria registrar a posição de cada palavra "token" e então combinar o up-to-5-words<that-position>"token"up-to-5-words para cada uma dessas posições.

Algo como:

$ echo 6 5 4 3 2 1 token token 1 2 3 4 5 6 | perl -lne '
    my @positions; push @positions, $-[0] while /\btoken\b/g;
    for $o (@positions) {
      print $& if /(\w+\W+){0,5}(?<=^.{$o})token(\W+\w+){0,5}/
    }'
5 4 3 2 1 token token 1 2 3 4
4 3 2 1 token token 1 2 3 4 5

Ou para esclarecer qual token está sendo correspondido em cada caso:

$ echo 6 5 4 3 2 1 token token 1 2 3 4 5 6 | perl -lne '
    my @positions; push @positions, $-[0] while /\btoken\b/g;
    for $o (@positions) {
      print "$1<token>$3" if /((\w+\W+){0,5})(?<=^.{$o})token((\W+\w+){0,5})/
    }'
5 4 3 2 1 <token> token 1 2 3 4
4 3 2 1 token <token> 1 2 3 4 5

(Eu esperaria que pudesse ser simplificado / otimizado).

    
por 05.10.2017 / 20:34