Reputation: 29
I'd like to find the quickest way to change a string of a list with a different types inside, into a list.
For example:
string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
into
list = [['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]
I know that the module ast
provides function that could help, but it only works when:
string = '[["Date1","Date2","Number1","Number2"],["28Dec2018","29Dec2018",1.24,5]]'
Thanks
Upvotes: 1
Views: 112
Reputation: 16772
string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
print(string.strip("[]").split(","))
OUTPUT:
['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']
EDIT:
string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
st = string.strip("[]").replace("[", "").replace("]", "").split(",")
listA = []
listB = []
c = 0
for s in st:
c = c + 1
if c <= 4:
if s.isdigit():
listA.append(int(s))
elif re.match("^\d+?\.\d+?$", s):
listA.append(float(s))
else:
listA.append(s)
else:
if s.isdigit():
listB.append(int(s))
elif re.match("^\d+?\.\d+?$", s):
listB.append(float(s))
else:
listB.append(s)
print([listA, listB])
OUTPUT:
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]
OR
If you don't want to convert the int
and float
then its even shorter:
for s in st:
c = c + 1
if c <= 4:
listA.append(s)
else:
listB.append(s)
print([listA, listB])
OUTPUT:
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']]
OR
As suggested by @Bhathiya Perera in the comments, a one liner killer using yaml:
import yaml
print(yaml.safe_load(string))
Upvotes: 2
Reputation: 82899
You could use a regular expression to detect everything that does not seem to be a number. Then, re.sub
all those non-numbers with themselves in quotes, i.e. `r'"\1"'
>>> string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
>>> re.findall(r"(?<=[,\[])(\w*[a-zA-Z]\w*)(?=[,\]])", string)
['Date1', 'Date2', 'Number1', 'Number2', '28Dec2018', '29Dec2018']
>>> re.sub(r"(?<=[,\[])(\w*[a-zA-Z]\w*)(?=[,\]])", r'"\1"', string)
'[["Date1","Date2","Number1","Number2"],["28Dec2018","29Dec2018",1.24,5]]'
This is a bit ugly, so let's break that down a bit:
(?<=[,\[])
: preceeded by ,
or [
(\w*[a-zA-Z]\w*)
: letters or digits, actually a letter, and more letters or digits(?=[,\]])
: followed by ,
or ]
Now, your string is valid JSON1) and can be parsed as such with the json
module:
>>> import json
>>> json.loads(_)
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]
This works for the examples given in your question. For other strings, the "letters or digits"-part of the regex would have to be revamped considerably. Alternatively, you might just wrap everything in quotes...
>>> re.sub(r"([^,\[\]]+)", r'"\1"', string)
"[['Date1','Date2','Number1','Number2'],['28Dec2018','29Dec2018','1.24','5']]"
>>> lst = json.loads(_)
... and then recursively cast to int
or float
whereever possible in a postprocessing step.
def try_to_cast(lst):
for i, x in enumerate(lst):
if isinstance(x, list):
try_to_cast(x)
else:
try:
lst[i] = float(x)
lst[i] = int(x)
except ValueError:
pass
>>> try_to_cast(lst)
>>> print(lst)
[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', 1.24, 5]]
1) As pointed out in comments, your string is already valid YAML and thus can just be parsed with the yaml
module without any pre- or postprocessing.
Upvotes: 1
Reputation: 3001
Here's a one liner utilizing split
, strip
and list comprehension;
string = '[[Date1,Date2,Number1,Number2],[28Dec2018,29Dec2018,1.24,5]]'
splitter = [x.split(',') for x in string.strip('[]').split('],[')]
print(splitter)
>>>[['Date1', 'Date2', 'Number1', 'Number2'], ['28Dec2018', '29Dec2018', '1.24', '5']]
Although as mentioned it doesn't capture the float/int, they return as strings.
Upvotes: 0