Skip to content

Instantly share code, notes, and snippets.

@1328
Last active August 29, 2015 14:19
Show Gist options
  • Select an option

  • Save 1328/9d7babae7f6e9286dfb2 to your computer and use it in GitHub Desktop.

Select an option

Save 1328/9d7babae7f6e9286dfb2 to your computer and use it in GitHub Desktop.
parser 2
from collections import namedtuple
Action = namedtuple('Action', ['verb', 'noun', 'adjective', 'indirect'])
NOUNS = ['sword', 'dog', 'hat']
VERBS = ['get', 'go', 'eat', 'north', 'east']
PREPOSITIONS = [
'below', 'off', 'toward', 'above', 'beneath', 'on', 'under',
'across', 'beside', 'from', 'onto', 'underneath', 'between',
'in', 'out', 'until', 'against', 'beyond',
'outside', 'along', 'inside', 'over', 'upon', 'among',
'by', 'past', 'around', 'with', 'at ', 'into',
'within', 'down', 'through', 'without', 'before',
'near', 'throughout', 'behind', 'except', 'of', 'to'
]
CINNAMONS = {'walk':'go', 'consume':'eat', 'n': 'north'}
ELIDE = ['the', 'a']
def parse(command):
''' break words into a list, substituing common synonyms, and
return Action '''
words = [CINNAMONS.get(w, w) for w in command.split() if w not in ELIDE]
return create_action(words)
def parse_preposition(words):
'''parses prepositional phrases
works by finding the last preposition and then cutting off remainder of
words
'''
last = None
for idx, word in enumerate(words):
if word in PREPOSITIONS:
last = idx
if last is None or last > len(words)-2:
return words, None, None
remaining = [w for idx, w in enumerate(words) if idx < last]
preposition = words[last]
indirect = words[last+1]
return remaining, preposition, indirect
def parse_adjective(words):
'''In a sufficiently long string, treat the word preceding a noun as an
adjective'''
if len(words) == 0:
return [], None, None
found, noun = None, None
remaining = []
for idx, word in enumerate(words):
if word in NOUNS:
found = idx
noun = word
break
if len(words)<2:
# only one owrd left so no adjective
if noun is not None:
return [], noun, None
return [], words[0], None
if noun is None:
# if we don't match a noun, just make a guess that it is the last word
noun = word[-1]
idx = len(words) - 1
used = (idx, idx -1)
remaining = [w for idx, w in enumerate(words) if idx not in used]
return remaining, words[idx], words[idx-1]
def parse_verb(words):
remaining = []
verb = None
for word in words:
if word in VERBS:
verb = word
else:
remaining.append(word)
if verb is None:
# hmm, could not match a verb, so just assume the first word of words is
# a verb and return that
return words[1:], words[0]
return remaining, verb
def create_action(words):
#print('create_action called on {}, kws = {}'.format(words, [(k,v) for k,v in kws.items()]))
words, verb = parse_verb(words)
words, preposition, indirect = parse_preposition(words)
words, noun, adjective = parse_adjective(words)
return Action(verb, noun, adjective, indirect)
check = [
'north',
'n',
'eat hat',
'consume hat',
'consume green hat',
'get dog from table',
'get orange dog from table',
'get orange dog from under',
'get orange dog from under table',
'get orange dog from under pink table', # doesn't work too complex
'get the really, really big sword',
]
for phrase in check:
print('"{}" => {}'.format(phrase, parse(phrase)))
print('-'*10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment