Вы можете использовать
library(gsubfn)
chf <- "(Mn,Ca,Zn)5(AsO4)2((AsO3)OH)24(H2O)(OH(AsO3))(OH(AsO3)OH)"
gsubfn("\\((?:[^()]++|(?R))*\\)", ~ gsub("(^\\(|\\)$)|[()]", "\\1", x, perl=TRUE), chf, perl=TRUE, backref=0)
# => [1] "(Mn,Ca,Zn)5(AsO4)2(AsO3OH)24(H2O)(OHAsO3)(OHAsO3OH)"
\((?:[^()]++|(?R))*\)
регулярное выражение - это известный PCRE-шаблон для соответствия вложенным скобкам. Как только совпадение найдено, gsubfn
берет строку и удаляет все не начальные и не окончательные скобки, используя gsub("(^\\(|\\)$)|[()]", "\\1", x, perl=TRUE)
. Здесь (^\\(|\\)$)
соответствует и захватывает первый (
и последний )
в группу 1, а затем любые (
и )
сопоставляются с [()]
. Заменой является содержание группы 1.
Базовое эквивалентное решение R:
chf <- "(Mn,Ca,Zn)5(AsO4)2((AsO3)OH)24(H2O)(OH(AsO3))(OH(AsO3)OH)"
gre <- gregexpr("\\((?:[^()]++|(?R))*\\)", chf, perl=TRUE)
matches <- regmatches(chf, gre)
regmatches(chf, gre) <- lapply(matches, gsub, pattern="(^\\(|\\)$)|[()]", replacement="\\1")
> chf
# => "(Mn,Ca,Zn)5(AsO4)2(AsO3OH)24(H2O)(OHAsO3)(OHAsO3OH)"