|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +''' |
| 3 | +Given a flat file of book metadata, write a Library class that parses the book data and provides an API that lets you search for all books containing a word. |
| 4 | +
|
| 5 | +API: |
| 6 | +
|
| 7 | +Library |
| 8 | +- <constructor>(input) -> returns a Library object |
| 9 | +- search(word) -> returns all books that contain the word anywhere in the |
| 10 | + title, author, or description fields. Only matches *whole* words. |
| 11 | +E.g. Searching for "My" or "book" would match a book containing "My book", but searching for "My b" or "boo" would *not* match. |
| 12 | +''' |
| 13 | +import re |
| 14 | + |
| 15 | + |
| 16 | +LIBRARY_DATA = """ |
| 17 | +TITLE: Hitchhiker's Guide to the Galaxy |
| 18 | +AUTHOR: Douglas Adams |
| 19 | +DESCRIPTION: Seconds before the Earth is demolished to make way for a galactic freeway, |
| 20 | +Arthur Dent is plucked off the planet by his friend Ford Prefect, a researcher for the |
| 21 | +revised edition of The Hitchhiker's Guide to the Galaxy who, for the last fifteen years, |
| 22 | +has been posing as an out-of-work actor. |
| 23 | +
|
| 24 | +TITLE: Dune |
| 25 | +AUTHOR: Frank Herbert |
| 26 | +DESCRIPTION: The troubles begin when stewardship of Arrakis is transferred by the |
| 27 | +Emperor from the Harkonnen Noble House to House Atreides. The Harkonnens don't want to |
| 28 | +give up their privilege, though, and through sabotage and treachery they cast young |
| 29 | +Duke Paul Atreides out into the planet's harsh environment to die. There he falls in |
| 30 | +with the Fremen, a tribe of desert dwellers who become the basis of the army with which |
| 31 | +he will reclaim what's rightfully his. Paul Atreides, though, is far more than just a |
| 32 | +usurped duke. He might be the end product of a very long-term genetic experiment |
| 33 | +designed to breed a super human; he might be a messiah. His struggle is at the center |
| 34 | +of a nexus of powerful people and events, and the repercussions will be felt throughout |
| 35 | +the Imperium. |
| 36 | +
|
| 37 | +TITLE: A Song Of Ice And Fire Series |
| 38 | +AUTHOR: George R.R. Martin |
| 39 | +DESCRIPTION: As the Seven Kingdoms face a generation-long winter, the noble Stark family |
| 40 | +confronts the poisonous plots of the rival Lannisters, the emergence of the |
| 41 | +White Walkers, the arrival of barbarian hordes, and other threats. |
| 42 | +
|
| 43 | +""" |
| 44 | + |
| 45 | + |
| 46 | +def remove_non_alpha_chars(s): |
| 47 | + s = s.replace("\n", " ") |
| 48 | + s = re.sub("[^a-zA-Z0-9\s']+", "", s) |
| 49 | + return s.strip() |
| 50 | + |
| 51 | + |
| 52 | +class Book: |
| 53 | + def __init__(self, title, author, desc): |
| 54 | + self.title = remove_non_alpha_chars(title) |
| 55 | + self.author = remove_non_alpha_chars(author) |
| 56 | + self.description = remove_non_alpha_chars(desc) |
| 57 | + |
| 58 | + words = set(self.title.split(" ")) |
| 59 | + words = words.union(set(self.author.split(" "))) |
| 60 | + words = words.union(set(self.description.split(" "))) |
| 61 | + self.words = words |
| 62 | + |
| 63 | + |
| 64 | +class Library: |
| 65 | + |
| 66 | + def __init__(self, data): |
| 67 | + |
| 68 | + book_text = data.split("\n\n") |
| 69 | + self.books = [] |
| 70 | + for t in book_text: |
| 71 | + if not t: |
| 72 | + continue |
| 73 | + |
| 74 | + m = re.search('.*TITLE:(.*)AUTHOR:(.*)DESCRIPTION:(.*)', t, re.DOTALL) |
| 75 | + |
| 76 | + title = m.group(1) |
| 77 | + author = m.group(2) |
| 78 | + description = m.group(3) |
| 79 | + self.books.append(Book(title, author, description)) |
| 80 | + |
| 81 | + def search(self, word): |
| 82 | + results = [] |
| 83 | + for b in self.books: |
| 84 | + if word in b.words: |
| 85 | + results.append(b) |
| 86 | + return results |
| 87 | + |
| 88 | + |
| 89 | +library = Library(LIBRARY_DATA) |
| 90 | +first_results = library.search("Arrakis") |
| 91 | +assert first_results[0].title == "Dune" |
| 92 | +second_results = library.search("winter") |
| 93 | +assert second_results[0].title == "A Song Of Ice And Fire Series" |
| 94 | +third_results = library.search("demolished") |
| 95 | +assert third_results[0].title == "Hitchhiker's Guide to the Galaxy" |
| 96 | +fourth_results = library.search("the") |
| 97 | +assert len(fourth_results) == 3 |
| 98 | +assert fourth_results[1].title == "Dune" |
| 99 | +assert fourth_results[2].title == "A Song Of Ice And Fire Series" |
| 100 | +assert fourth_results[0].title == "Hitchhiker's Guide to the Galaxy" |
| 101 | +print("All tests passed!") |
0 commit comments