Как я могу извлечь текст между круглыми скобками, содержащими определенное слово?

Как может я преобразовывать это:

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

К этому:

foo bar 80
foo blat 92

Я хотел бы сохранить весь текст, который НЕ находится в круглых скобках.

Я только хочу извлечь текст между круглыми скобками, которые содержат строки "панель" или "блеют" в них.

Пары круглых скобок, которые не содержат, "блеют", или "панель" должна быть проигнорирована.

Sed или awk будут очень предпочтены

4
задан 3 April 2018 в 19:06

5 ответов

В то время как это действительно возможно в sed или awk, это намного легче (для меня, так или иначе) использование Perl:

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

Объяснение

  • -ple : print каждая строка входного файла, после executing сценарий на нем. -l удаляет запаздывание новых строк и добавляет новую строку к каждому вызову print.
  • @pars=( /(\(.+?\))/g ); : @pars массив теперь содержит все строки, которые являются в круглых скобках.
  • for $par (@pars){ ... } : для каждой из строк, найденных выше.
  • s/\s*.$par.// unless $par=~/blat|bar/ : удалите этот набор круглых скобок, если они не содержат blat или bar.
  • s/[()]//g; : Раскройте все скобки (не текст в них).

Вы могли также играть в гольф, уплотняют вышеупомянутое к

perl -ple 'for$par((/(\(.+?\))/g)){$par=~/blat|bar/||s/\s*.$par.//};s/[()]//g;' file
3
ответ дан 23 November 2019 в 11:39

Используя sed:

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

Входной файл:

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

Выходной файл:

test bar blat
bar testblat bartest
blat testbar barblat blatanother

Разбивка :

#1:

  • (: соответствует ( символ
  • \(: начинает группировать группу фиксации
  • [^\)]*: соответствия 0 или больше символов не )
  • \(: начинает группировать позволенные строки
  • bar: соответствует 1-й позволенной строке
  • \|: разделяет 2-ю позволенную строку
  • blat: соответствует 2-й позволенной строке
  • \): остановки, группирующие позволенные строки
  • [^\)]*: соответствия 0 или больше символов не )
  • \): остановки, группирующие группу фиксации
  • ): соответствует ) символ

#2:

  • (: соответствует ( символ
  • .*: соответствия 0 или больше символов
  • ): соответствует ) символ
  • : соответствует символ
5
ответ дан 23 November 2019 в 11:39

Используя 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())

Вывод:

foo bar 80
foo blat 92
  • Здесь мы использовали re (Регулярное выражение) модуль python.
  • pat_list будет содержать список строк в круглых скобках
  • Тогда, мы искали присутствие, "блеют" или "панель" в эти pat_list участники
  • , Если не найденный, мы распечатали строку, раскрывающую ненужные части включая скобки.
3
ответ дан 23 November 2019 в 11:39

Используя awk:
Сохраните следующий код в текстовый файл и сделайте его исполняемым файлом (chmod u+x filename).

Затем выполните его как это:

awk -f filename inputfile

Это огромно по сравнению с решениями в perl или python, Я добавляю это просто потому что awk или sed было предпочтительное решение и показать, что возможно использовать awk даже при том, что это не удобно.

{
#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
}
3
ответ дан 23 November 2019 в 11:39

мало поздно, но, что относительно этого, питания короткой простоты:

> 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
0
ответ дан 23 November 2019 в 11:39

Другие вопросы по тегам:

Похожие вопросы: