# How parse nicely a string into three (or more) pieces?

See, I have a file which consists of a bunch of lines like

NAME:0001;some text
ANOTHERNAME:000103;some more text
NEWNAME:42; blah blah


So what I need to do is to have a list of those names, list of numbers (IDs actually, so the order matters) and list of further comments. I wrote a code, which actually does work, but I'm afraid it's horrible and not pythonic at all.

reactions_file = open("reactions.txt","r")
reaction_names = []
reaction_other = []
reaction_IDs = []
reaction_notes = []
for line in lines:
r_name = line.partition(":")[0]
r_other = line.partition(":")[2]
reaction_names.append(r_name)
reaction_other.append(r_other)
for item in reaction_other:
r_ID = item.partition(";")[0]
r_note = item.partition(";")[2]
reaction_IDs.append(r_ID)
reaction_notes.append(r_note)
print(reaction_names)
print(reaction_IDs)
print(reaction_notes)
reactions_file.close()


How can it be changed to look less like written by newbie? :)

You can say:

>>> import re
>>> re.split('[:;]', 'NAME:0001;some text')
['NAME', '0001', 'some text']

• Seems like you could improve that by checking only for upper case, then colon then digits then semi colon, otherwise any time the last group has either of those two characters, you're going to be dealing with all kinds of craziness. Outside the scope of the question, I guess. – TankorSmash Dec 13 '13 at 15:31
• I'd suggest maybe storing the result for each line as a namedtuple (docs.python.org/2/library/collections.html) or dictionary for easier access in the rest of the code – theodox Dec 16 '13 at 21:32

Here's a solution that works without importing Regex (though it's worth noting that Regex is extremely powerful and worth learning)!

This solution:

• Has one for loop
• Looks at each line, replaces all ; with :, and then splits each line into 3 parts.
• Adds each part to their respective lists.
• Prints each list afterwards.

Here is the code:

reactions_file = open("reactions.txt","r")
names = []
ids = []
notes = []

for line in lines:
names.append(line.replace(';',':').split(':')[0])
ids.append(line.replace(';',':').split(':')[1])
notes.append(line.replace(';',':').split(':')[2])

print(names)
print(ids)
print(notes)

reactions_file.close()


A note: One weakness is that if your "notes" section has a : anywhere in it, the note will be cut off at that :. There are fixes for this obviously, namely the regex method. But, this method is logically simple and you may follow it more easily.

## Breakdown of the solution

#You know what these do
reactions_file = open("reactions.txt","r")
names = []
ids = []
notes = []


Let's look at each of the split lines, using placeholder names for a general case.

placeholderlist.append(line.replace(';',':').split(':')[i])


In this operation, things are processed from left to right inside the first set of parentheses.

For this case, say the line in question is james:0001;Hello world

The first operation is line.replace(';',':') which turns line into:

james:0001:Hello world


Then comes .split(':'), which splits a string into any number of parts, each one separated by :.

Then comes indexing-- have you ever touched upon indexes?

When Python splits something, or there is a list, or even in strings, there exists indexes. It starts from the left to the right, at position 0 and progressing to position n, the end of the list/string/etc.

Example:

string = "Hello world"
print(string[0])
print(string[3])
print(string[4])


Produces:

>>H
>>l
>>o


Similarly, a list will give you element n in its list. So when we run split(':')[i] on line:

print(line.replace(';',':').split(':')[0])
print(line.replace(';',':').split(':')[1])
print(line.replace(';',':').split(':')[2])


We get

>>james
>>0001
>>Hello world


But that's not enough! We want to put them into your lists, names, ids, and notes.

For this we use .append(), which simply adds element to list.

As such, for each loop we add the name, the id, and the notes to their respective lists. At the end, we print each list to verify.

You should find each list will be exactly what you want provided no : is in your notes

Any questions? Feel free to comment (tag my name with @jwarner112) and I'll show back up to help.

Happy Coding!