Como posso extrair texto entre parênteses contendo uma palavra específica?

4

Como posso converter isso:

foo (blah) (bar 80)
foo (cats) (blat 92)

Para isso:

foo bar 80
foo blat 92

Eu gostaria de manter todo o texto que NÃO está entre parênteses.

Eu só quero extrair texto entre parênteses que contenham as strings "bar" ou "blat" nelas.

Os pares de parênteses que não contêm "blat" ou "bar" devem ser ignorados.

Sed ou awk serão muito preferidos

    
por TuxForLife 29.04.2015 / 18:59

5 respostas

3

Embora isso seja realmente possível em sed ou awk , é muito mais fácil (para mim, de qualquer maneira) usar o Perl:

$ perl -ple '@pars=( /(\(.+?\))/g ); 
              for $par (@pars){
                s/\s*.$par.// unless $par=~/blat|bar/
              } s/[()]//g;' file
foo bar 80
foo blat 92

Explicação

  • -ple : p rint cada linha do arquivo de entrada, depois de e xecutando o script nele. O -l remove as novas linhas finais e adiciona uma nova linha a cada chamada de print .
  • @pars=( /(\(.+?\))/g ); : a matriz @pars agora contém todas as cadeias que estão entre parênteses.
  • for $par (@pars){ ... } : para cada uma das strings encontradas acima.
  • s/\s*.$par.// unless $par=~/blat|bar/ : remova este conjunto de parênteses se eles não contiverem blat ou bar .
  • s/[()]//g; : remova todos os parênteses (não o texto dentro deles).

Você também pode golf condensar o acima para

perl -ple 'for$par((/(\(.+?\))/g)){$par=~/blat|bar/||s/\s*.$par.//};s/[()]//g;' file
    
por terdon 29.04.2015 / 19:38
5

Usando sed :

< inputfile sed 's/(\([^\)]*\(bar\|blat\)[^\)]*\))//g; s/(.*) //g'

Arquivo de entrada:

test (bar) (blat)
bar (testblat) (bartest)
blat (testbar) (barblat) (no) (blatanother)

Arquivo de saída:

test bar blat
bar testblat bartest
blat testbar barblat blatanother

Repartição :

# 1:

  • ( : corresponde a um caractere (
  • \( : inicia o agrupamento do grupo de captura
  • [^\)]* : corresponde a 0 ou mais caracteres que não são )
  • \( : inicia o agrupamento das strings permitidas
  • bar : corresponde à primeira string permitida
  • \| : separa a segunda string permitida
  • blat : corresponde à segunda cadeia permitida
  • \) : para de agrupar as strings permitidas
  • [^\)]* : corresponde a 0 ou mais caracteres que não são )
  • \) : para de agrupar o grupo de captura
  • ) : corresponde a um caractere )

# 2:

  • ( : corresponde a um caractere (
  • .* : corresponde a 0 ou mais caracteres
  • ) : corresponde a um caractere )
  • : corresponde a um caractere
por kos 30.04.2015 / 13:47
3

Usando python :

#!/usr/bin/env python2
import re
with open('/path/to/file.txt') as f:
    for line in f:
        pat_list = re.findall(r'\(([^)]*?)\)', line.rstrip())
        for pat in pat_list:
            if not re.search(r'(?:blat|bar)', pat):
                print re.sub(r'\(|\)', '', line.replace(' ({0})'.format(pat), '').rstrip())

Saída:

foo bar 80
foo blat 92
  • Aqui usamos o módulo re (Expressão Regular) de python .
  • pat_list conterá a lista de strings entre parênteses
  • Em seguida, pesquisamos a presença de "blat" ou "bar" nos membros pat_list
  • Se não encontrado, imprimimos a linha removendo partes desnecessárias, incluindo parênteses.
por heemayl 29.04.2015 / 20:32
3

Usando awk :
Salve o seguinte código em um arquivo de texto e torne-o executável ( chmod u+x filename ).

Em seguida, execute-o assim:

awk -f filename inputfile

Isso é imenso comparado às soluções em perl ou python , estou adicionando isso apenas porque awk ou sed foi a solução preferida e para mostrar que é possível usar awk , embora seja não é conveniente.

{
#list of words to look for in parentheses: (named "w" to speed up adding items)
w[0] = "bar";
w[1] = "blat";

#"bool" value whether of not to crop spaces around omitted parenthesis with their content
cropSpaces = 1;

spaces = 0;                     #space counter used for cropping 
open = 0;                       #open/nested parenthesis counter
st = 0;                         #marks index where parenthesis starts
end = 0;                        #marks index where parenthesis ends
out = 0;                        #"bool" value indicating whether or not the word has been found
for(i = 1;i-1 < length($0);i++){     #for each character
  c = substr($0,i,1);                 #get character
  if(c == "("){                       #character is '('
    open++;                            #increment parenthesis counter
    if(open == 1) st = i+1;            #marks start of parenthesis (if not nested)
  }
  else if(c == ")"){                 #char is ')'
    open--;                           #decrement parenthesis counter
    if(open == 0) end = i;            #mark end of parenthesis (if not nested)
  }
  else{                             #any other char
    if(open == 0){                   #outside of parenthesis
      if(cropSpaces && c == " "){     #char is space (and cropSpaces option is not 0) 
        if(spaces == 0) printf c;      #print space if not sequential  
        spaces++;                      #increment space counter
      }
      else{                           #any other char
        spaces = 0;                    #set previous spaces counter to 0
        printf c;                      #print char
      }
    }
    else if(!out){                   #inside of parenthesis (and no word has been found)
      for(j = 0; j < length(w); j++){               #for every word in list
        if( substr( $0,i,length(w[j]) ) == w[j]){    #if word matches
          out = 1;                                    #word has been found
          break;                                      #do not look for any other words
        }
      }
    }
  }
  if(open == 0 && out){              #outside of parenthesis and word found in previous parenthesis
    printf substr($0,st,end-st);      #print content
    out = 0;                          #reset "word found" indicator 
    spaces = 0;                       #reset spaces counter
  }
}

printf "\n";                        #print newline
}
    
por curusarn 30.04.2015 / 13:25
0

pouco atrasado mas, e quanto a isso, poder da simplicidade on-line:

> cat test.py
from string import replace

stuff = '''
foo (blah) (bar 80)
foo (cats) (blat 92)
'''

for i in stuff.split('\n'):  # split by \n
  if i != str():  # not empty string
    print ''.join(i.split()[0]+' '+i.split()[2]+' '+i.split()[3]).replace('(','').replace(')','')

>>> python test.py 
foo bar 80
foo blat 92
    
por user814493 03.04.2018 / 23:18