Соответствие переменной количества вхождений токена с использованием регулярных выражений в Python - PullRequest
0 голосов
/ 27 октября 2018

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

Мой текст выглядит примерно так:

&{dict1_name}=   key1=key1value   key2=key2value
&{dict2_name}=   key1=key1value

Таким образом, в основном несколько строк, каждая из которых содержит начальную строку, пробелы, а затем переменное количество пар ключей. Если вам интересно, откуда это взялось, это файл переменных каркаса робота, который я пытаюсь преобразовать в файл переменных Python.

Я буду выполнять итерацию для каждой строки, чтобы найти пары ключей и составить из них словарь Python.

Мой текущий шаблон регулярных выражений:

&{([^ ]+)}=[ ]{2,}(?:[ ]{2,}([^\s=]+)=([^\s=]+))+

Это правильно дает мне имя вхождения, но пары ключей соответствуют только последнему вхождению, как упомянуто выше. Как я могу получить его, чтобы он возвращал кортеж, содержащий: ("dict1_name","key1","key1value"..."keyn","keynvalue"), чтобы я мог затем перебрать его и построить словарь python так:

dict1_name= {"key1": "key1value",..."keyn": "keynvalue"}

Спасибо!

Ответы [ 4 ]

0 голосов
/ 30 октября 2018

Построение Ответ Брэда , я внес некоторые изменения.Как упомянуто в моем комментарии к его ответу, это потерпело неудачу в пустых строках или строках комментариев.Я изменил это, чтобы игнорировать их и продолжить.Я также добавил обработку пробелов: теперь он совпадает с пробелами в именах словаря, но заменяет их подчеркиванием, поскольку в python не может быть пробелов в именах переменных.Ключи остаются нетронутыми, поскольку они являются строками.

import re


    def robot_to_python(filename):
        """
        This function can be used to convert robot variable files containing dicts to a python
        variables file containing python dict that can be imported by both python and robot.
        """
        dname = re.compile(r"^&{(?P<name>.+)}=")
        keyval = re.compile(r"(?P<key>[\w|:]+)=(?P<val>[\w|:]+)")

        data = {}
        with open(filename + '.robot') as f:
            for line in f:
                n = dname.search(line)
                if n:
                    name = dname.search(line).group("name").replace(" ", "_")

                    if name:
                        data[name] = dict(keyval.findall(line))

        with open(filename + '.py', 'w') as file:
            for dictionary in data.items():
                dict_name = dictionary[0]
                file.write(dict_name + " = { \n")
                keyvals = dictionary[1]
                for k in sorted(keyvals.keys()):
                    file.write("'%s':'%s', \n" % (k, keyvals[k]))
                file.write("}\n\n")
        file.close()
0 голосов
/ 27 октября 2018

Используйте два выражения в сочетании с пониманием слова:

import re

junkystring = """
lorem ipsum
&{dict1_name}=   key1=key1value   key2=key2value
&{dict2_name}=   key1=key1value
lorem ipsum
"""

rx_outer = re.compile(r'^&{(?P<dict_name>[^{}]+)}(?P<values>.+)', re.M)
rx_inner = re.compile(r'(?P<key>\w+)=(?P<value>\w+)')

result = {m_outer.group('dict_name'): {m_inner.group('key'): m_inner.group('value')
            for m_inner in rx_inner.finditer(m_outer.group('values'))}
            for m_outer in rx_outer.finditer(junkystring)}

print(result)

Который производит

{'dict1_name': {'key1': 'key1value', 'key2': 'key2value'}, 
 'dict2_name': {'key1': 'key1value'}}


С двумя выражениями
^&{(?P<dict_name>[^{}]+)}(?P<values>.+)
# the outer format

См. демонстрацию на regex101.com . И второй

(?P<key>\w+)=(?P<value>\w+)
# the key/value pairs

См. демонстрацию для последнего на regex101.com .

Остальное - просто сортировка различных выражений в понимании dict.

0 голосов
/ 27 октября 2018

Как вы указали, вам нужно будет обойти тот факт, что группы захвата будут ловить только последний матч. Один из способов сделать это - использовать тот факт, что строки в файле являются итеративными, и использовать два шаблона: один для «имени строки» и один для нескольких пар значений ключа: *

import re

dname = re.compile(r'^&{(?P<name>\w+)}=')
keyval = re.compile(r'(?P<key>\w+)=(?P<val>\w+)')

data = {}
with open('input/keyvals.txt') as f:
    for line in f:
        name = dname.search(line)
        if name:
            name = name.group('name')
            data[name] = dict(keyval.findall(line))

* Правда, это немного неэффективно, так как вы проводите два поиска в строке. Но для файлов среднего размера, вам подойдет.

Результат:

>>> from pprint import pprint
>>> pprint(data)
{'d5': {'key1': '28f_s', 'key2': 'key2value'},
 'name1': {'key1': '5', 'key2': 'x'},
 'othername2': {'key1': 'key1value', 'key2': '7'}}

Обратите внимание, что \w соответствует символам слова Unicode.


Пример ввода, keyvals.txt:

&{name1}=   key1=5   key2=x
&{othername2}=   key1=key1value   key2=7
&{d5}=   key1=28f_s   key2=aaa key2=key2value
0 голосов
/ 27 октября 2018

Вы можете использовать два регулярных выражения, одно для имен, а другое для элементов, применяя одно для элементов после первого пробела:

import re

lines = ['&{dict1_name}=   key1=key1value   key2=key2value',
         '&{dict2_name}=   key1=key1value']

name = re.compile('^&\{(\w+)\}=')
item = re.compile('(\w+)=(\w+)')

for line in lines:
    n = name.search(line).group(1)
    i = '{{{}}}'.format(','.join("'{}' : '{}'".format(m.group(1), m.group(2)) for m in item.finditer(' '.join(line.split()[1:]))))
    exec('{} = {}'.format(n, i))
    print(locals()[n])

выход

{'key2': 'key2value', 'key1': 'key1value'}
{'key1': 'key1value'}

Объяснение

'^&\{(\w+)\}=' соответствует '&', за которым следует слово (\w+), окруженное фигурными скобками '\{', '\}'. Второе регулярное выражение соответствует любым словам, соединенным '='. Линия:

i = '{{{}}}'.format(','.join("'{}' : '{}'".format(m.group(1), m.group(2)) for m in item.finditer(' '.join(line.split()[1:]))))

создает словарь-литерал, и, наконец, вы создаете словарь с нужным именем, используя exec. Вы можете получить доступ к значению словаря запросов местных жителей.

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