Grouping regex matches per line in python

Viewed 73

I am extracting results from a (poorly coded) python file, a sample of what I am looking at is as follows:

 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"

I am looking to make a .json parallel array using this information to index it, following the following format "ENCHANTED_BREAD": ["enchanted bread", "ebread", "bread"]

I am trying to create a regex to find all the aliases of the return value. So far I thought about using the following REGEX as I already extracted the return values and organised them as keys:

=="(.*?)"

but the issue with it is that I won't be able to "group" the values to assign multiple to a single key. Since the values corresponding to the same key are on the same line it is probably the way to go.

What can I use in regex to be able to group the regex matches per line?

Thank you for your help.

2 Answers

I haven't run this to check syntax, but perhaps something like:

regex = "if (\(name == \"\w+\"\)( or )?)+\n\sreturn (\"[\w\s]+\")"

Explanation: \w is equivalent to [a-zA-Z0-9_] (i.e. alphanumeric or underscore) \s is whitespace

So we match the if, then match a group with the (name == "some_string") with an optional or as many times as possible (minimum of once), then match the newline, then whitespace until the return statement, when we match a group for the return value.

For each match this regex provides, you should get these two groups, one containing all the possible valid inputs and the second group with the output.

Hopefully that gets you most of the way to a full solution.

Link to documentation: https://docs.python.org/3/howto/regex.html

As an alternative you could interleave the results from name capture and return capture using the or (|) operator. For the regex to capture the aliases of the return value, and the return string itself, you can use [^"]+ to group any character that it's not a " one or more times.

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>[^"]+)"|return\s+"(?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"],
}
Related