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\$