Группировка совпадений регулярных выражений в строке в python

#python #regex

Вопрос:

Я извлекаю результаты из (плохо закодированного) файла python, пример того, на что я смотрю, выглядит следующим образом:

  if (name == "wheat"):
    return "WHEAT"
if (name == "enchanted bread") or (name == "ebread") or (name == "bread"):
    return "ENCHANTED_BREAD"
if (name == "hay bale") or (name == "haybale"):
    return "HAY_BLOCK"
if (name == "enchanted hay bale") or (name == "ebale") or (name == "ehayblock"):
    return "ENCHANTED_HAY_BLOCK"
if (name == "tightly-tied hay bale") or (name == "tightly tied hay bale"):
    return "TIGHTLY_TIED_HAY_BALE"
 

Я хочу создать параллельный массив .json, используя эту информацию для его индексации, в следующем формате «ЗАЧАРОВАННЫЙ хлеб»: [«зачарованный хлеб», «ebread», «хлеб»]

Я пытаюсь создать регулярное выражение, чтобы найти все псевдонимы возвращаемого значения. До сих пор я думал об использовании следующего РЕГУЛЯРНОГО выражения, поскольку я уже извлек возвращаемые значения и организовал их как ключи:

 =="(.*?)"
 

но проблема в том, что я не смогу «сгруппировать» значения, чтобы назначить несколько одному ключу. Поскольку значения, соответствующие одному и тому же ключу, находятся в одной строке, это, вероятно, правильный путь.

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

Спасибо вам за вашу помощь.

Ответ №1:

Я запустил это не для проверки синтаксиса, но, возможно, что-то вроде:

 regex = "if ((name == "w ")( or )?) nsreturn ("[ws] ")"
 

Объяснение:
w эквивалентно [a-zA-Z0-9_] (т. е. буквенно-цифровому или подчеркиванию)
s является пробелом

Поэтому мы сопоставляем if , затем сопоставляем группу (name == "some_string") с необязательным or как можно больше раз (минимум один раз), затем сопоставляем новую строку, затем пробелы до оператора return, когда мы сопоставляем группу для возвращаемого значения.

Для каждого соответствия, которое обеспечивает это регулярное выражение, вы должны получить эти две группы, одна из которых содержит все возможные допустимые входные данные, а вторая группа-выходные данные.

Надеюсь, это поможет вам пройти большую часть пути к полному решению.

Ссылка на документацию: https://docs.python.org/3/howto/regex.html

Ответ №2:

В качестве альтернативы вы можете чередовать результаты name захвата и return захвата с помощью оператора or ( | ). Чтобы регулярное выражение фиксировало псевдонимы возвращаемого значения и саму возвращаемую строку, вы можете использовать [^"] для группировки любого символа, который не является " одним или несколькими разами.

 import re

data = '''
 if (name == "wheat"):
    return "WHEAT"
if (name == "enchanted bread") or (name == "ebread") or (name == "bread"):
    return "ENCHANTED_BREAD"
if (name == "hay bale") or (name == "haybale"):
    return "HAY_BLOCK"
if (name == "enchanted hay bale") or (name == "ebale") or (name == "ehayblock"):
    return "ENCHANTED_HAY_BLOCK"
if (name == "tightly-tied hay bale") or (name == "tightly tied hay bale"):
    return "TIGHTLY_TIED_HAY_BALE"
'''

regex = r'(name == "(?P<opts>[^"] )"|returns "(?P<catg>[^"] )"'
r_iter = re.finditer(regex, data)

tmp_opts = []
result = {}
for m in r_iter:
    if m.group('catg'):
        result[m.group('catg')] = tmp_opts
        tmp_opts = []
    else:
        tmp_opts.append(m.group('opts'))

print(result)
 
 {
    "WHEAT": ["wheat"],
    "ENCHANTED_BREAD": ["enchanted bread", "ebread", "bread"],
    "HAY_BLOCK": ["hay bale", "haybale"],
    "ENCHANTED_HAY_BLOCK": ["enchanted hay bale", "ebale", "ehayblock"],
    "TIGHTLY_TIED_HAY_BALE": ["tightly-tied hay bale", "tightly tied hay bale"],
}