Given a string representation of data, I want to extract the information into its corresponding object.
However,
If the string has "|" separators then these should be considered options and need to be picked at random.
If the string data has numbers shown as a range "1-10" then a random value should be chosen between the range. It should also preserve the numerical datatype i.e int or float
I.e
"(1-3,1,1)" returns either (1, 1, 1), (2, 1, 1) or (3, 1, 1)
"(0.2-0.4,1,1)" returns either (0.2, 1, 1), (0.3, 1, 1) or (0.4, 1, 1)
"foo|bar|foobar" returns either "foo", "bar" or "foobar"
"[1-2,1,2]|foo|bar|[1,8-10,99]" could return :
"foo","bar", [1, 1, 2], [2, 1, 2], [1, 8, 99], [1, 9, 99] or [1, 10, 99]
This is what I have and it works well. But I cant help think it could be achieved in a more concise way. Let me know what I could have done better.
import re import random import ast def randomize_by_pipe(st_value): """ Used to split strings with the pipe character and randomly choose and option. :param: st_value - (str) """ if not st_value is None: st_arr = st_value.split("|") random.shuffle(st_arr) return st_arr[0] else: return st_value def randomise_range(text): if text is None: return text else: matches = re.findall("\d*\.*\d*-{1}\d*\.*\d*",text) for match in matches: startingPos = 0 position = text.find(match, startingPos) while True: position = text.find(match, startingPos) if position > -1: txt = text[position:position+len(match)] txt = rand_no_from_string(txt) new_text = text[0:position+len(match)].replace(match,str(txt)) text = new_text + text[position+len(match):] else: break try: return ast.literal_eval(text) except ValueError: return text def rand_no_from_string(txt): is_int = False txt_arr = txt.split("-") num_arr = [float(x) for x in txt_arr] if int(num_arr[0]) == num_arr[0]: mul = 1 is_int = True else: #new section to deal with the decimals mul = 10 ** len(str(num_arr[0]).split(".")[1]) num_arr = [x*mul for x in num_arr] if num_arr[0] > num_arr[1]: num_arr[1], num_arr[0] = num_arr[0], num_arr[1] val = random.randint(num_arr[0],num_arr[1])/mul return int(val) if is_int else val
Run with:
text="(108-100,0.25-0.75,100)|Foo|Bar|[123,234,234-250]" randomise_range(randomize_by_pipe(text))
text = "(0.2-0.4,1,1)"
, which you say returns either (0.2, 1, 1), (0.3, 1, 1) or (0.4, 1, 1), and it didn't work. I got (0.324, 1, 1) iinstead.\$\endgroup\$