Como posso excluir texto que NÃO está entre aspas ou parênteses?

5

Entrada:

19. "foo foo" (bar bar) (19) raboof
"foo foo" raboof

Resultado esperado:

"foo foo" (bar bar) (19)
"foo foo"

Como você pode ver, gostaria de manter as aspas duplas e parênteses.

Tudo o que não estiver entre aspas duplas ou parênteses deve ser removido.

    
por TuxForLife 01.05.2015 / 19:48

8 respostas

10

Usando python :

#!/usr/bin/env python2
import re, sys
with open(sys.argv[1]) as f:
    for line in f:
        parts = line.split()
        for i in parts:
            if re.search(r'^[("].*[)"]$', i):
                print i,
        print '\n'.lstrip()

Saída:

"foo" (bar) (19) 
"foo"
  • Cada linha é lida e as partes separadas por espaços são salvas em uma lista chamada parts

  • Em seguida, usando a função re do módulo search , encontramos as partes que começam com " ou ( e terminam com " ou ) .

Como executar:

Salve o script como, por exemplo, %código%. Agora você pode executá-lo de duas maneiras:

  • Torne-o executável por script.py e execute-o como chmod u+x /path/to/script.py , ou seja, insira o arquivo /path/to/script.py /path/to/file.txt como o primeiro argumento. Se o script e o arquivo estiverem no mesmo diretório, então a partir desse diretório file.txt

  • Você pode executá-lo sem torná-lo executável, executá-lo como ./script.py file.txt .

Responda à pergunta editada:

#!/usr/bin/env python2
import re, sys
with open(sys.argv[1]) as f:
    for line in f:
        print ''.join(re.findall(r'(?:(?<=\s)["(].*[")](?=\s|$)|(?<=^)["(].*[")](?=\s|$))', line))

Saída:

"foo foo" (bar bar) (19)
"foo foo"
    
por heemayl 01.05.2015 / 20:21
5

Nova versão (espaços permitidos entre () ou "" ):

Experimente o comando abaixo perl (credits: @ steeldriver )

perl -ne 'printf "%s\n", join(" " , $_ =~ /["(].*?[)"]/g)'

Versão inicial (sem espaços entre () ou "" )

Você pode tentar o seguinte perl oneliner:

$ perl -ne '@a=split(/\s+/, $_); for (@a) {print "$_ " if /[("].*?[)"]/ };print"\n"'  file
    
por Sylvain Pineau 01.05.2015 / 21:09
4

Outra opção em python:

#!/usr/bin/env python3
import sys
match = lambda ch1, ch2, w: all([w.startswith(ch1), w.endswith(ch2)])

for l in open(sys.argv[1]).read().splitlines():
    matches = [w for w in l.split() if any([match("(", ")", w), match('"', '"', w)])]
    print((" ").join(matches))
  • Copie o script em um arquivo vazio, salve o script como filter.py

  • Execute-o com o comando:

    python3 /path/to/filter.py <file>
    

Na versão editada da pergunta:

Se assumirmos que existe um caractere closing em todos os caracteres abertura : '(' e '"' (devemos supor que, já que, caso contrário, o arquivo estaria incorreto ou a pergunta teria que mencionar um conjunto mais complexo de regras no caso de parênteses ou citações "aninhadas", o código abaixo também deveria funcionar:

#!/usr/bin/env python3
import sys
chunks = lambda l: [l[i:i + 2] for i in range(0, len(l), 2)]

for l in open(sys.argv[1]).read().splitlines():
    words = chunks([i for i in range(len(l)) if l[i] in ['(', ')', '"']])
    print((" ").join([l[w[0]:w[1]+1] for w in words]))

Lista os caracteres na lista: ['(', ')', '"'] , produz pedaços de dois dos resultados encontrados e imprime o que está no intervalo de cada par:

19. "foo" (bar bar) (blub blub blub blub) (19) raboof
"foo" raboof

irá então imprimir:

"foo" (bar bar) (blub blub blub blub) (19)
"foo"

O uso é exatamente igual ao primeiro script.

Mais ou outros "gatilhos" podem ser facilmente adicionados adicionando os dois lados (caractere inicial e final da string ou seção para "manter") na lista:

['(', ')', '"']

na linha:

words = chunks([i for i in range(len(l)) if l[i] in ['(', ')', '"']])
    
por Jacob Vlijm 01.05.2015 / 21:04
3

Se você (ou alguém com um problema semelhante que leia isso) não precisa preservar as novas linhas, o seguinte funcionaria:

grep -Eo '"[^"]*"|\([^)]*\)'

Para entrada

19. "foo foo" (bar bar) (19) raboof
"foo foo" raboof

produz saída

"foo foo"
(bar bar)
(19)
"foo foo"

Se você precisar de novas linhas, use alguns truques, por exemplo, isso:

sed 's/$/$/' \
| grep -Eo '"[^"]*"|\([^)]*\)|$$' \
| tr '\n$' ' \n' \
| sed 's/^ //'

O primeiro sed adiciona $ ao final de cada linha. (Você pode usar qualquer caractere para isso.) O segundo é quase o mesmo grep acima, mas agora também corresponde a $ no final de uma linha, para que corresponda a cada fim de linha. O tr transforma novas linhas em espaços e dólares em novas linhas. Mas como a saída antes que tr tenha $ seguido de nova linha, a saída depois terá nova linha seguida de espaço. O% final sed se livra desses espaços.

    
por MvG 01.05.2015 / 22:10
3

Como perl script:

$filename=$ARGV[0];
if (open(my $fh, '<:encoding(UTF-8)', $filename)) {
  while (my $match = <$fh>) {
    while ($match =~ /((\(.*?[^)]\))|(".*?"))/g) {
      print " ";
    }
    print "\n"
  }
}

Ou como perl one-liner:

perl -ne 'while (/((\(.*?[^)]\))|(".*?"))/g) {print " ";} print "\n"' file

Resultado

"foo foo" (bar bar) (19) 
"foo foo"

Essa foi a tarefa original :

  

Entrada:

     
  1. "foo" (bar) (19)
  2.   

raboof "foo" raboof

     

Resultado esperado:

     

"foo" (bar) (19)

     

"foo"

Usando perl :

perl -pe '@elements=( split (/\s/) ); 
    for $element (@elements) {
        if ($element!~/^"|\(/ and $element!~/"|\($/) {
            s/$element//
        }
        s/^\s+//;
        s/\s+$/\n/
    };' file

ou como one-liner:

perl -pe '@elements=( split (/\s/) ); for $element (@elements) { if ($element!~/^"|\(/ and $element!~/"|\($/) { s/$element// } s/^\s+//; s/\s+$/\n/ };' file

Saída:

"foo" (bar) (19)
"foo"
    
por A.B. 01.05.2015 / 21:15
2

Outro perl :

$ perl -nle 'print join " ", $_ =~ /".*?"|\(.*?\)/g' file
"foo foo" (bar bar) (19)
"foo foo"
    
por cuonglm 02.05.2015 / 18:19
2

Abaixo, um código Python simples fará esse trabalho.

import re
with open('file') as f:
    reg = re.compile(r'"[^"]*"|\([^)]*\)')
    for line in f:
        print(' '.join(reg.findall(line)))

E outro através do Perl que usa apenas regex,

$ perl -pe 's/(?:"[^"]*"|\([^)]*\))(*SKIP)(*F)|\S//g;s/^\h+|\h+$|(\h)+//g' file
"foo foo" (bar bar) (19)
"foo foo"
    
por Avinash Raj 02.05.2015 / 18:53
1

PHP seria:

if (preg_match_all('/"(?:[^"\\]+|\\.)+"|\([^)]+\)/', $input, $matches)) {
  echo implode(' ', $matches[0]);
}

Isso também lida corretamente com caracteres de escape dentro de strings entre aspas (por exemplo, "Test \"string\"" é tratado como uma string.

    
por thomasrutter 03.05.2015 / 16:56