Как отметил @Giacomo, вложенные скобки требуют сложных регулярных выражений. Вам будет лучше использовать собственный синтаксический анализатор, который может справиться с каждым случаем. Вы все еще можете использовать регулярные выражения, но это не обязательно должно быть one-regex-to-rule-them-all .
import re
def comma_partition(s):
"""Partitions `s` at top-level commas"""
s = s.strip('{').strip('}')
in_parens = 0
ixs = []
for i, c in enumerate(s):
if c == '(':
in_parens += 1
if c == ')':
in_parens -= 1
if not in_parens and c == ',':
ixs.append(i)
return [s[sc] for sc in make_partition_slices(ixs)]
def make_partition_slices(ixs):
"""Yields partitioning slices, skipping each index of `ixs`"""
ix_x = [None] + ixs
ix_y = ixs + [None]
for x, y in zip(ix_x, ix_y):
yield slice(x + 1 if x else x, y)
def kv_parser(kv_str):
"""Takes a string in 'K:V' format and returns dictionary.
Leading namespace in `V` is removed.
"""
k, v = kv_str.split(':', 1)
v = re.sub(f'^([A-Za-z_]([A-Za-z0-9_])*\.)+', '', v)
return {k: v}
Выше мы определили 3 функции, одну для нахождения индексов запятых верхнего уровня (тех, которые не в скобках). Это делается путем простого подсчета открытых и закрытых скобок. Вторая функция генерирует фрагменты, которые будут разделять строку слева и справа от каждого индекса для запятых. Третий - фактический синтаксический анализатор, который разделяет ключ и значение и очищает пространство имен значений, используя простое регулярное выражение.
Ниже мы запустим его в вашем тестовом примере.
s = '{a:bilby.core.prior.Uniform(-1,1,a, func=g(1, 2)),b:2}'
out = {}
for p in comma_partition(s):
out.update(kv_parser(p))
out
# returns:
{'a': 'Uniform(-1,1,a, func=g(1, 2))', 'b': '2'}
Это это больше кода, но гораздо НАМНОГО легче изменить и поддерживать, чем сложное регулярное выражение.