3
\$\begingroup\$

I have a data file that looks like this:

Friend Name                     Joe
Likes                           Jill
Age                             30
Gender                          Male

Friend Name                     
Likes                           Mark
Age                             30
Gender                          Male

Friend Name                     Bob
Likes                           Ralph
Age                             30
Gender                          Male

Note: the data file has leading spaces before the first column.

I want to parse this file and see who likes a given person (likes). In this example, at most only one person likes the given person. So, say I am finding who likes 'Ralph', only Bob does. It is possible that the likes is not even in the data. It is also possible that the Friend Name might be blank (see the second Friend).

Here is my code to parse this data and return the friend who likes 'likes':

def parse_friends_list(friends_list, likes):
    output = friends_list.strip().splitlines()
    for line in output:
        try:
            if line.startswith('Friend Name'):
                friend = line.split()[2]
            elif line.startswith('Likes'):
                found_likes = line.split()[1]
                if found_likes == likes and friend:
                    return friend
                friend = ''
        except IndexError:
            pass
    raise NoFriendParse('Unable to find a friend for {}'.format(likes))
\$\endgroup\$
  • \$\begingroup\$ In your example data, does the second stanza mean that a nameless 30-year-old male likes Mark? \$\endgroup\$ – 200_success Mar 17 '15 at 21:49
  • \$\begingroup\$ In this case, yes :( I was trying to ensure that I could catch missing information \$\endgroup\$ – Mark Mar 17 '15 at 21:53
2
\$\begingroup\$

I like to break problems like this up into a few steps, makes it easier for my brain to understand.

import re

raw_text = """Friend Name                     Joe
Likes                           Jill
Age                             30
Gender                          Male

Friend Name
Likes                           Mark
Age                             30
Gender                          Male

Friend Name                     Bob
Likes                           Ralph
Age                             30
Gender                          Male"""


def split_row(row):
    items = re.split('\s\s+', row)
    if len(items) < 2:  # Value is blank
        return items[0], None
    return items


def parse_block(block):
    rows = block.split('\n')
    fields = map(split_row, rows)
    return dict(fields)


def process_text(text):
    blocks = text.split('\n\n')
    return map(parse_block, blocks)

if __name__ == '__main__':
    for like in process_text(raw_text):
        print(like)

Which generates the output

{'Likes': 'Jill', 'Friend Name': 'Joe', 'Age': '30', 'Gender': 'Male'}
{'Likes': 'Mark', 'Friend Name': None, 'Age': '30', 'Gender': 'Male'}
{'Likes': 'Ralph', 'Friend Name': 'Bob', 'Age': '30', 'Gender': 'Male'}
\$\endgroup\$
0
\$\begingroup\$

I would parse the input string once, and then search in the objects for likes or whatever else you're looking for:

teststring = """Friend Name                     Joe
Likes                           Jill
Age                             30
Gender                          Male

Friend Name
Likes                           Mark
Age                             30
Gender                          Male

Friend Name                     Bob
Likes                           Ralph
Age                             30
Gender                          Male"""

def parseString(s):
    l=[]
    d={}
    for line in s.split("\n"):
        spl = list(filter(bool,map(str.strip,line.split("  "))))
        if len(spl)==2:
            d[spl[0]] = spl[1]
        else:
            if bool(d):
                l.append(d)
            d={}
    return l

def likes(objects, who):
    for obj in objects:
        if obj["Likes"] == who:
            return obj["Friend Name"]
    raise NoFriendParse('Unable to find a friend for {}'.format(who))

data = parseString(teststring)
print(likes(data,"Jill")) #prints "Joe"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.