Преобразование строки в словарь строк с внутренней запятой - PullRequest
3 голосов
/ 12 февраля 2020

Я пытаюсь построить регулярное выражение для преобразования строки, которая преобразует это

'{a:bilby.core.prior.Uniform(-1,1,a, func=g(1, 2)),b:2}'

в

{"a": "Uniform(-1,1,a, func=g(1, 2))", "b": "2"}

Обратите внимание, что значения словаря по-прежнему строки (они будут впоследствии интерпретируется другой функцией)

Пока что у меня есть это

>>> import re
>>> re.sub(r'([A-Za-z/\.0-9\-\+][^\[\],:"}]*)', r'"\g<1>"', '{a:bilby.core.prior.Uniform(-1,1,a, func=g(1, 2)),b:2}')
'{"a":"bilby.core.prior.Uniform(-1","1","a", "func=g(1", "2))","b":"2"}'

Но проблема в том, что она совпадает с запятой внутри скобки. Есть ли способ сопоставления, только если не в скобках?

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

1 Ответ

3 голосов
/ 12 февраля 2020

Как отметил @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'}

Это это больше кода, но гораздо НАМНОГО легче изменить и поддерживать, чем сложное регулярное выражение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...