Ваш лучший вариант - использовать GNU awk для любого из них:
$ awk '{$0=gensub(/(##)(code)/,"\\1before\\2",1)} 1' <<<'##code'
##beforecode
$ awk 'match($0,/(##)(code)/,a){$0=a[1] "before" a[2]} 1' <<<'##code'
##beforecode
Первый позволяет перемещать только текстовые сегменты, а второй позволяет вызывать функции, выполнять математические операции или делать что-либо еще.на соответствующий текст, прежде чем перемещать его в оригинале или делать с ним что-то еще:
$ awk 'match($0,/(##)(code)/,a){$0=length(a[1])*10 "before" toupper(a[2])} 1' <<<'##code'
20beforeCODE
Подумав немного, я не знаю, как получить желаемое поведение любым разумным способомиспользуя только POSIX awk конструкции.Вот что я попробовал (функция matches()
):
$ cat tst.awk
BEGIN {
str = "foobar"
re = "(f.*o)(b.*r)"
printf "\nre \"%s\" matching string \"%s\"\n", re, str
print "succ: gensub(): ", gensub(re,"<\\1> <\\2>",1,str)
print "succ: match(): ", (match(str,re,a) ? "<" a[1] "> <" a[2] ">" : "")
print "succ: matches(): ", (matches(str,re,a) ? "<" a[1] "> <" a[2] ">" : "")
str = "foofoo"
re = "(f.*o)(f.*o)"
printf "\nre \"%s\" matching string \"%s\"\n", re, str
print "succ: gensub(): ", gensub(re,"<\\1> <\\2>",1,str)
print "succ: match(): ", (match(str,re,a) ? "<" a[1] "> <" a[2] ">" : "")
print "fail: matches(): ", (matches(str,re,a) ? "<" a[1] "> <" a[2] ">" : "")
}
function matches(str,re,arr, start,tgt,n,i,segs) {
delete arr
if ( start=match(str,re) ) {
tgt = substr($0,RSTART,RLENGTH)
n = split(re,segs,/[)(]+/) - 1
for (i=1; RSTART && (i < n); i++) {
if ( match(str,segs[i+1]) ) {
arr[i] = substr(str,RSTART,RLENGTH)
str = substr(str,RSTART+RLENGTH)
}
}
}
return start
}
.
$ awk -f tst.awk
re "(f.*o)(b.*r)" matching string "foobar"
succ: gensub(): <foo> <bar>
succ: match(): <foo> <bar>
succ: matches(): <foo> <bar>
re "(f.*o)(f.*o)" matching string "foofoo"
succ: gensub(): <foo> <foo>
succ: match(): <foo> <foo>
fail: matches(): <foofoo> <>
, но, конечно, это не работает для второго случая в качестве первого сегмента RE f.*o
соответствует всей строке foofoo
, и, конечно, то же самое происходит, если вы пытаетесь взять RE сегменты в обратном порядке.Я также рассмотрел получение сегментов RE, как описано выше, но затем строил новую строку по одному символу за раз из переданной строки и сравнивал первый сегмент RE с THAT, пока он не совпадет, поскольку TH будет самой короткой подходящей строкой для сегмента RE, НОэто не подходит для строки + RE, например:
str='foooobar'
re='(f.*o)(b.*r)'
, поскольку f.*o
будет соответствовать foo
с этим алгоритмом, когда оно действительно должно соответствовать fooooo
.
Итак - яПолагаю, вам нужно будет продолжать выполнять итерации (внимательно следя за тем, в каком направлении вы выполняете итерацию - с конца, как я полагаю, правильно), пока строка не будет разбита на сегменты, каждый из которых соответствует каждому сегменту RE самым левым-самым длинным образом.Похоже, много работы!