Execution of distributive property using regex

Viewed 94

I am trying to change the order using regex, but running into a problem with alternative groups.

Example: 1a,1b,1c ABC
Output: ABC*1a,ABC*1b,ABC*1c

Example: 1a,2b ABC
Output: ABC*1a,ABC*2b

Example: 1a ABC
Output: ABC*1a

So far what I have is:

re.sub(r'((\d\W,\d\W,\d\W)|(\d\W,\d\W)|(\d\W))()(\d\W\d\W\d\W)',r'\3\*\1',string)

Any ideas on how to deal with the possible subgroups?

4 Answers

I see that the question is about regular expressions, but what as @Ronald stated using them to entirely swap the content would be rather difficult. This is an example how you could use them and combine them with python methods to achieve the results that you are looking for:

import re

def parse_string_1(str_):
    prog1 = re.compile('([\d\w]*)[\,\s]')
    prog2 = re.compile('\s(\w*)')

    constant = re.findall(prog2, str_)[0]
    multipliers = re.findall(prog1, str_)

    result = []
    for multiplier in multipliers: 
        result.append(f"{constant}*{multiplier}")
    return ','.join(result)

parse_string_1("1a,1b,1c ABC")
>>> ABC*1a,ABC*1b,ABC*1c
parse_string_1("1a,2b ABC")
>>> ABC*1a,ABC*2b
parse_string_1("1a ABC")
>>> ABC*1a

If you can leave them completely you could do this:

def parse_string_2(str_):
    result = []
    multipliers, constant = str_.split(' ')
    for multiplier in multipliers.split(','):
        result.append(f"{constant}*{multiplier}")
    return ','.join(result)

parse_string_2("1a,1b,1c ABC")
>>> ABC*1a,ABC*1b,ABC*1c
parse_string_2("1a,2b ABC")
>>> ABC*1a,ABC*2b
parse_string_2("1a ABC")
>>> ABC*1a

Without using regular expressions, you may consider to use itertools.product:

from itertools import product
data=['1a,1b,1c ABC', '1a,2b ABC', '1a ABC']

for s in data:
    lst = [e.split(',') for e in s.split()]
    for prod in product(*lst):
        print('{}*{}'.format(prod[1], prod[0]))

Maybe something like:

import re
str = '1a,1b,1c ABC'
print(re.sub(r'(?=\d)', str.split()[1]+'*', str.split()[0]))

Result:

ABC*1a,ABC*1b,ABC*1c

For that data structure, you might also use the regex PyPi module and the \G anchor

(?:\G(\d[a-zA-Z]+,?)| ([A-Z]+))

Explanation

  • (?: Non capture group
    • \G Assert the end of the previous match
    • (\d[a-zA-Z]+,?) Capture group 1, match 1+ times a char a-zA-Z and optional ,
    • | Or
    • ([A-Z]+) Capture group 1, match a space and 1+ chars A-Z
  • ) Close group

Regex demo | Python demo

import regex

strings = [
    "1a,1b,1c ABC",
    "1a,2b ABC",
    "1a ABC"
]

for s in strings:
    tuples = regex.findall(r"(?:\G(\d[a-zA-Z]+,?)| ([A-Z]+))", s)
    prefix = ''.join(tuples.pop())
    result = "".join(f"{prefix}*{t[0]}" for t in tuples)
    print(result)

Output

ABC*1a,ABC*1b,ABC*1c
ABC*1a,ABC*2b
ABC*1a
Related