Как может я преобразовывать это:
foo (blah) (bar 80)
foo (cats) (blat 92)
К этому:
foo bar 80
foo blat 92
Я хотел бы сохранить весь текст, который НЕ находится в круглых скобках.
Я только хочу извлечь текст между круглыми скобками, которые содержат строки "панель" или "блеют" в них.
Пары круглых скобок, которые не содержат, "блеют", или "панель" должна быть проигнорирована.
Sed или awk будут очень предпочтены
В то время как это действительно возможно в 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
: p
rint каждая строка входного файла, после e
xecuting сценарий на нем. -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
Используя 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 или больше символов )
: соответствует )
символ
: соответствует
символ Используя 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
участники Используя 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
}
мало поздно, но, что относительно этого, питания короткой простоты:
> 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