#!/usr/bin/python """ seagent context { isa API, agent, pythonModule; description "This is a API for agents who can read and write on the (data ocean)". reads Pentals, N-Triples, Semenglish, N3, RDF/XML, KIF, CycL; writes Pentals, N-Triples, Semenglish, N3, RDF/XML, KIF, CycL, HTML; theory seeUrl ; preceededBy CyberMind; forums , ; author (Seth Russell); credits (segent people); downloads , , , ; licenseUrl ; version 0.043; revised "05/26/2002 10am"; status writing, testing; inProgress0 "revise output stragegy ...always return data, then output(say())"; inProgress1 ; nextToDo1 "process imparatives"; nextToDo2 "show attn with html highlight ..."; thinkingAbout0 "changeing Arrow -> Object"; thinkingAbout1 "compound subjects with grammar enlosing in parenthesis (Seth Russell)"; lastProgress "sbp revised parsePentals"; priorProgress "translated __doc__ string to Semenglish"; }. (seagent people) context { (Seth Russell) preferedEmail ; homePage ; knownHandels "Seth","SethR"; (seagent credits) (original authorship). (Sean B Palmer) preferedEmail ; homePage ?homePage; (seagent credits) parsePentals knownHandels "sbp"? (Daniel Biddle) preferedEmail ; homePage ?homePage; (seagent credits) "see seaboat"; knownHandels "deltab"? (Mark Russell) preferedEmail ; homePage ?homePage; knownHandels ?knownHandels; (seagent credits) "prodced original CyberMind on which data structure is based"? }. (data ocean) context { description "The (data ocean) was mis-metaphored (semantic web) by (Tim Berners-Lee) ~1995. The (data ocean) is based on the memory structures of graphs containing labeled arrows relating nodes Graphs are related to the natural language concept called 'context'"; seeUrl . }. """ __license__= 'Copyright (C) 2001 Seth Russell. GNU GPL 2' import types import sys import re global ok, fail, oh fail=0 ok=1 oh=2 class wake: def __init__(self,MyName='I',ownedBy='nobody'): # Acquire my identity from imput arguments self.MyName=MyName self.Owner=ownedBy # The Logical State Value for Trivalent Logic # Logic is set by methods: ok, fail, oh # To values: 'ok', 'fail', 'oh' # These states are tested by methods: then, else, ohthen # the third logical value, 'oh', is sometimes refered to as 'surprise' # set to surprise here because attn is not yet on an arrow self.Logic='oh' # This variable exposes the descripiton of the last error # Usually Logic is set to 'oh' whenever an error occurs # @@@ ? @@@ any method which can error, must set error='' prior to execuition # @@@ Proposed change: strategy with surprise and pushing errors on a stack ? self.error='' # Things are identified in this system by integer serial numbers # A thing's integer serial numbers is refered to as it's id # A thing's type, given by thingType(id), is coded in the high order decimal digit of an id # 99,000,000 should be enough grains of sand for the moment # The following assignments fix the thingType for various kinds of things self.graphIdFix = 100000000 # thingType='Graph' self.nodeIdFix = 200000000 # thingType='Node' self.open3IdFix = 300000000 # thingType='3unused' self.arrowIdFix = 400000000 # thingType='Arrow' self.lexIdFix = 500000000 # thingType='Lex' self.open6IdFix = 600000000 # thingType='6unused' self.numberIdFix= 700000000 # thingType='Number' self.actionIdFix= 800000000 # thingType='Program' self.open9IdFix = 900000000 # thingType='9unused' # Start the ids where they left off in the Persistent Data Storage(PDS) # @@@@@ initilized to blank here because we havent gotten to that yet self.PDS='' if self.PDS == '': # If starting a new PDS, start all Ids from their fixes self.graphId=self.graphIdFix self.nodeId=self.nodeIdFix self.arrowId=self.arrowIdFix self.lexId=self.lexIdFix self.numberId=self.numberIdFix self.actionId=self.actionIdFix # The structure of mentography in python is a python list # of graphs, of nodes, of predicates, of arrows to objects # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # This list called graphs contains the actual mentograph in Memory self.graphs=[] # Initilize the attn pointers into these graphs # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # red pointers in mentograph are moved when navigating attn self.attnGraph=0 self.attnNode=0 self.attnPredicate=0 self.attnArrow=0 # There are two dictionaies as seen in green in the mentograph # seeUrl http://robustai.net/mentography/python_Memory_structure.gif # The lexicon {symbal : id } which associates a symbal with an id self.lexicon={} # associations look like {id : [ symbal, (graph1,node1), (graph2,node2), ...] } # provides the symbal associated with the id and a list of which graphs in which that id exists self.associations={} # the stack for mem and remem contains tuples of attn # [(attnGraph,attnNode,attnPredicate,attnArrow) ... ] self.memStack=[] # commands that are permissable to run in the interperter # currently we are very permissable self.commands =dir(self) # Let's grow the first arrow in the first node in the first graph # so that attn from this point on is alway closed on the graph. self.groGraph('UrGraph') # from the input parameters making an instance of wake # Asserting the Pental (in default of any args) that {I ownedBy NoBody UrGraph.}. # assert first pent that {MyName ownedBy Owner UrGraph.} self.groNode(self.Owner) self.groNode(self.MyName) self.groPredicate('ownedBy') self.groArrow(self.Owner) # kludge for memo self.memo=() # ----- END INITILIZE wake instance self.Logic='ok' return None # ----------------------------------------------------- # ---------------- AN QUIDTY INTERPERTER ------------ # ----------------------------------------------------- def doit(self, toDo): # toDo is a list of lists like: [[command1, arg1], [command2, arg2] ... ] for do in toDo: if do[0] in self.commands: method = getattr(self, do[0]) if do[1]=='': method() else: method(do[1]) # ----------------------------------------------------- # ---------------- NAVIGATION METHODS ----------------- # ----------------------------------------------------- # MOVING BETWEEN GRAPHS def firstGraph(self): self.attnGraph=0 self.firstNode() return self.Attn() def nextGraph(self): if self.attnGraph+2>=len(self.graphs): self.firstGraph() self.Logic='fail' return fail else: self.attnGraph+=2 self.firstNode() self.Logic='ok' return ok def lastGraph(self): self.attnGraph=len(self.graphs)-2 self.firstNode() return self.Attn() # MOVING BETWEEN NODES IN A GRAPH def firstNode(self): self.attnNode,self.attnPredicate,self.attnArrow=0,0,0 return self.Attn() def jace(self): if self.attnNode+2>=len(self.graphs[self.attnGraph]): self.firstNode() self.Logic='fail' return fail else: self.attnNode+=2 self.attnPredicate,self.attnArrow=0,0 self.Logic='ok' return ok def lastNode(self): self.attnNode=len(self.graphs[self.attnGraph])-2 self.attnPredicate,self.attnArrow=0,0 return self.Attn() # MOVING BETWEEN PREDICATES IN A NODE def firstPredicate(self): self.attnPredicate,self.attnArrow=0,0 return self.Attn() def sym(self): if self.attnPredicate+3>=len(self.graphs[self.attnGraph][self.attnNode]): self.attnPredicate,self.attnArrow=0,0 self.Logic='fail' return fail else: self.attnPredicate+=3 self.attnArrow=0 self.Logic='ok' return ok def lastPredicate(self): self.attnPredicate=len(self.graphs[self.attnGraph][self.attnNode])-3 self.attnArrow=0 return self.Attn() def symTo(self,property): if property==None and len(self.graphs[self.attnGraph][self.attnNode])==0: self.Logic='ok' return ok if thingType(property)=='NotThing': if property==None: id=None elif self.lexicon.has_key(property): id=self.lexicon[property] else: self.Logic='fail' return fail else: id=property self.firstPredicate() self.Logic='ok' while self.Logic=='ok': if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]==id: break self.sym() if self.Logic=='ok': return ok return fail # MOVING BETWEEN ARROWS IN A PREDICATE def firstArrow(self): self.attnArrow=0 return self.Attn() def gress(self): if self.attnArrow+3>=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate]): self.attnArrow=0 self.Logic='fail' return fail else: self.attnArrow+=3 self.Logic='ok' return ok def gressTo(self,object): if object==None and self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow]==None: self.Logic='ok' return ok if thingType(object)=='NotThing': if object==None: id=None elif self.lexicon.has_key(object): id=self.lexicon[object] else: self.Logic='fail' return fail else: id=object self.firstArrow() self.Logic='ok' while self.Logic=='ok': if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]==id: break self.gress() if self.Logic=='ok': return ok return fail def lastArrow(self): self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 return self.Attn() # MANIPULATING ATTENTION ONLY def at(self,called): # find a node in any graph associated with this symbal # if not found in any grpah, make a node in attn graph # set attn to first arrow in node # Note, node may be a graph node if self.lexicon.has_key(called): id=self.lexicon[called] else: id=self.newNodeId(called) if self.associations.has_key(id): a=self.associations[id] self.attnGraph,self.attnNode = a[1][0], a[1][1] else: self.groNode(called) self.associations[id]=[called, (self.attnGraph,self.attnNode)] self.attnPredicate, self.attnArrow = 0 , 0 return self.Attn() def mem(self): # push attn on the stack for future reference self.memStack.append((self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow)) def remem(self): # pop attn off the stack # if nothing on stack report error and be surprised if len(self.memStack)>0: self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow = self.memStack.pop() else: self.error='remem but nothing on memStack' self.Logic='oh' return oh # VANCE - FOLLOW YOUR ARROW TO IT'S DESTINATION def vance(self): if type(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow]) is types.TupleType: self.attnGraph,self.attnNode=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] self.attnPredicate,self.attnArrow=0,0 self.Logic='ok' return ok else: self.Logic='fail' return fail # ----------------------------------------------------- # ---------------- GROWTH METHODS --------------------- # ----------------------------------------------------- # ISSUE NEW IDENTITIES def newGraphId(self,called=None): if called==None: # new anonymous graph self.graphId+=1 return self.graphId elif self.lexicon.has_key(called): # we already have a graph\node called that return self.lexicon[called] else: # assign a new graphId and put it in lexicon self.graphId+=1 self.lexicon[called]=self.graphId return self.graphId def newNodeId(self,called=None): # Note: property nodes are just nodes if called==None: # new anonymous node self.nodeId+=1 return self.nodeId elif self.lexicon.has_key(called): # we already have a graph\node called that return self.lexicon[called] else: # assign a new nodeId and put it in lexicon self.nodeId+=1 self.lexicon[called]=self.nodeId return self.nodeId def newArrowId(self): # we dont give arrows identity at the moment # self.arrowId+=1 return None def newLexId(self, value, parseType='', language=''): # seeUrl http://rdfig.xmlhack.com/2002/05/01/2002-05-01.html#1020277030.932331 # seeUrl http://cvs.ilrt.org/cvsweb/~checkout~/redland/raptor/tests/test.nt if (value[0]=='"' and value[-1]=='"') or (value[0]=="'" and value[-1]=="'"): pass else: value='"'+value+'"' literal=parseType+value+language if self.lexicon.has_key(literal): # we already have such a literal return lexicon[literal] else: # assign a new lexId and put it in lexicon self.lexId+=1 self.lexicon[literal]=self.lexId return self.lexId # GROW GRAPHS, NODES, PREDICATES AND ARROWS def groGraph(self,called=None): # Grow a new graph with one empty node # The name of the graph is passed as the optional argument 'called' # fails: if graph exists, yet moves attn there # surprised: if graph name exists yet has not assoications or is not a graph # seeUrl self.error='' if called!=None: if self.lexicon.has_key(called): # can't make new graph, it already exists if self.associations.has_key(self.lexicon[called]): id=self.lexicon[called] if thingType(id)!='Graph': self.error='Attempt to groGraph called "'+called+'" but that name is already used, and is not a Graph.' self.logic='oh' return oh # set the Graph we found at Attn id=self.lexicon[called] self.attnGraph=self.associations[id][1] self.firstNode() self.Logic='fail' return fail else: # should not happen self.error='Attempt to groGraph called "'+called+'" which name is already used, yet is not associated with anything.' self.Logic='oh' return oh id=self.newGraphId(called) self.graphs.append([]) self.graphs.append(id) self.attnGraph=len(self.graphs)-2 self.associations[id]=[called] self.groNode(called) self.Logic='ok' return ok def groNode(self,called=None): # Grow a new node with one empty predicate # The name of the node is passed as the optional argument 'called' # fails: if node already exists, yet moves attn there # seeUrl id=self.newNodeId(called) # get the id for this node if self.associations.has_key(id): assn=self.associations[id] for i in assn: if type(i) is types.TupleType and i[0]==self.attnGraph: # go to that node in this graph self.attnNode=i[1] # but we failed to gro a new node # because one already existed with that id self.Logic='fail' return fail self.graphs[self.attnGraph].append([]) self.graphs[self.attnGraph].append(id) # move attn to new node self.attnNode=len(self.graphs[self.attnGraph])-2 self.attnPredicate,self.attnArrow=0,0 # add it to the associations dictionary if self.associations.has_key(id): self.associations[id].append((self.attnGraph,self.attnNode)) else: self.associations[id]=[called,(self.attnGraph,self.attnNode)] # gro a default empty predicate on it self.groPredicate() self.Logic='ok' return ok def groPredicate(self,property=None): # Grow a new predicate # The property name of the predicate is passed as the optional argument # fails: if predicate already exists on this node, yet moves attn there if property==None: self.graphs[self.attnGraph][self.attnNode].append([]) self.graphs[self.attnGraph][self.attnNode].append(None) self.graphs[self.attnGraph][self.attnNode].append(None) self.groArrow() return ok self.mem() self.at(property) id=self.graphs[self.attnGraph][self.attnNode+1] propertyLocation=self.attnGraph,self.attnNode self.remem() if self.symTo(id): # predicate already exists on this node, cannot gro a new one self.Logic='fail' return fail if self.symTo(None): self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+0]=[None,None,None] self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]=id self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+2]=propertyLocation return ok self.graphs[self.attnGraph][self.attnNode].append([]) self.graphs[self.attnGraph][self.attnNode].append(id) self.graphs[self.attnGraph][self.attnNode].append(propertyLocation) # move attn to new predicate self.attnPredicate=len(self.graphs[self.attnGraph][self.attnNode])-3 self.attnArrow=0 # gro a empty arrow here self.groArrow() self.Logic='ok' return ok def groArrow(self,object=None, seq=None): # Gro a new arrow to the object and place attn on the arrow # fails if arrow to object already exists, yet goes there # @@@@@ support for seq missing if object==None: self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 self.Logic='ok' return ok self.mem() self.at(object) id=self.graphs[self.attnGraph][self.attnNode+1] objectLocation=self.attnGraph,self.attnNode self.remem() if self.gressTo(id): # object already exists on this node, cannot gro a new one self.Logic='fail' return fail if self.gressTo(None): self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+0]=objectLocation self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]=id self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+2]=None return ok self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(objectLocation) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(id) self.graphs[self.attnGraph][self.attnNode][self.attnPredicate].append(None) # move attn to new arrow self.attnArrow=len(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate])-3 self.Logic='ok' return ok def gro(self,subject,predicate,object,graph=None,seq=None): # @@@@ process graph and seq arguments if present self.groNode(subject) self.groPredicate(predicate) self.groArrow(object) # ----------------------------------------------------- # ---------------- READ IN DATA FROM OUTSIDE ---------- # ----------------------------------------------------- def readPentals(self,xstimulus): # returns a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] stmts=parsePentals(xstimulus) #stmts is a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] #stmts is a list of tuples [(s[0] ,s[1] ,s[2] ,s[3],s[4],s[5] ), ...] #@@@ does not process seq and terminal performatives yet for s in stmts: if s[3]!='': self.groGraph(s[3]) self.groNode(s[0]) self.groPredicate(s[1]) self.groArrow(s[2]) # -------------------------------------------------------------------- # THESE METHODS RETRUN REPRESENTATIONS SUITABLE FOR HUMAN CONSUNPTION # -------------------------------------------------------------------- def sayArrow(self): # like saying a triple: subject predicate object. predicateId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1] if predicateId==None: return '' self.mem() predicateToken=self.associations[predicateId][0] r=self.sayTopic+predicateToken+self.sayObject() def say(self): predicateId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1] if predicateId==None: return fail self.mem() predicateToken=self.associations[predicateId][0] print predicateToken, self.sayObject() while self.gress(): print ',', self.sayObject() print self.remem() def sayObject(self): object=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] if object==None: return fail elif type(object) is types.TupleType: self.mem() if self.vance(): self.sayTopic() self.remem() return ok else: print object, def sayTopic(self): topicId=self.graphs[self.attnGraph][self.attnNode+1] if topicId==None: return fail topicToken=self.associations[topicId][0] print topicToken, return ok def sayBal(self): if self.ifEmptyPredicate(): return ok self.mem() self.sayTopic() print self.firstPredicate() print ' ', self.say() while self.sym(): print ' ', self.say() # print '.' self.remem() def ifEmptyPredicate(self): if self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]==None: self.Logic='ok' return ok self.Logic='fail' return fail def sayGraph(self): self.mem() self.firstNode() self.sayBal() while self.jace(): self.sayBal() self.remem() def sayGraphServer(self): saveStreams=sys.stdin, sys.stdout f=open('temp.txt', 'w') sys.stdout=f self.sayGraph() f.close() f=open('temp.txt', 'r') s='' for i in f: s=s+i f.close() l=s.replace('<','<') r=l.replace('>','>') return r def Attn(self): return self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow def dispAttnLogic(self): return (self.attnGraph, self.attnNode, self.attnPredicate, self.attnArrow),self.Logic # ----------------------------------------------------- # ---------------- DEBUGGING TOOLS -------------------- # ----------------------------------------------------- def showAssociations(self): a=self.associations.items() for i in a: print i[0],i[1] def showLexicon(self): a=self.lexicon.items() for i in a: print i[0],i[1] def showAttn(self): gId=self.graphs[self.attnGraph+1] print 'graph=',gId,self.symbalOf(gId) nId=self.graphs[self.attnGraph][self.attnNode+1] print 'node=',nId,self.symbalOf(nId) pId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1] print 'predicate=',pId,self.symbalOf(pId) object=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow] stId=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1] seq=self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+2] print 'object=',object,' stId=',stId,' seq=',seq def symbalOf(self,id): k=self.lexicon.items() for i in k: if i[1]==id: return i[0] return '' def showGraph(self): self.mem() self.savememo() print self.symbalOf(self.graphs[self.attnGraph+1]), print self.graphs[self.attnGraph+1] self.firstNode() self.Logic='ok' while self.Logic=='ok': self.showNode() self.jace() self.remem() def showNode(self): self.mem() print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode+1]), print self.graphs[self.attnGraph][self.attnNode+1], print self.Attn() self.firstPredicate() self.Logic='ok' while self.Logic=='ok': self.showPredicate() self.sym() self.remem() def showPredicate(self): print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1]), print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+1], print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate+2] self.showObjects() def showObjects(self): self.mem() self.firstArrow() self.Logic='ok' while self.Logic=='ok': print ' ', print self.symbalOf(self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1]), print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow+1], print self.graphs[self.attnGraph][self.attnNode][self.attnPredicate][self.attnArrow],self.showPlace() self.gress() self.remem() return None def showPlace(self): x=self.attnGraph,self.attnPredicate,self.attnNode,self.attnArrow if x==self.memo: return '<---' else: return '' def savememo(self): self.memo=self.attnGraph,self.attnPredicate,self.attnNode,self.attnArrow # --------- END WAKE METHODS ------------ # ---------FUNCTIONS IN THE MODULE AGENT FOLLOW---------------- def tokenType(called): # Tokens are elements of text read from external languages # This function classifies tokens # Symbals are tokens that refer to things but are not things in themselves # Symbals must contain at least one alphabetic character and not be enclosed in quotes # Symbals are sometimes called constants or variables in logical languages like KIF or CycL # Digits are numbers # Literals are data to be taken as is --- URI are literals # Punctuation is everything else # seeUrl http://robustai.net/mentography/types.gif if type(called)!=type('a'): return 'NotToken' elif called.isdigit(): return 'Digits' elif called.isalnum(): return 'Symbal' elif called[-1]=='"' or called[-1]=="'": return 'Literal' elif called[0]=='<' and called[-1]==">": return 'Uri' else: return 'Punctuation' def thingType(id): # This function classifies things according to # the high order digit of their id # seeUrl http://robustai.net/mentography/types.gif if type(id)!=type(100000000): return 'NotThing' if id < 100000000 or id > 999999999 : return 'NotThing' thingTypes=('NotThing','Graph','Node','3unused','Arrow','Lex','6unused','Number','Program','9unused') return thingTypes[int(str(id)[0])] def parsePentals(s, t=[]): # This lexical analizer was written by (Sean B Palmer) # revised to speed up and support compoundPhrase # seeUrl # returns a list of tuples [(subject,predicate,object,graph,seq,terminal), ...] t = t[:] ws = r'[ \t]' name = r'(?:\S+)' literal = r'(?:"[^"\\]*(?:\\.[^"\\]*)*")' comp = r'(?:\('+ws+r'*'+name+r'(?:'+ws+r'+'+name+r')+'+ws+r'*\))' term = r'('+literal+r'|'+comp+r'|'+name+r')' rt = r'^'+term+ws+r'+'+term+ws+r'+'+term+r'(?:'+ws+r'+'+term+r')?' \ r'(?:'+ws+r'+'+term+r')?'+ws+r'?([!?.])$' for line in s.replace('\r\n', '\n').replace('\r', '\n').split('\n'): match = re.compile(rt).findall(line)[:1] if match: t.append(match[0]) return t """ ___________________________________________________________________________________________ FLOATSAM ___________________________________________________________________________________________ def parsePentals(s, t=[]): a, t = r'("[^"\\]*(?:\\.[^"\\]*)*"|\S+)', t[:] rt = r'%s[ \t]%s[ \t]%s(?:[ \t]%s)?(?:[ \t]%s)?[ \t]?([!?.])' \ % (a, a, a, a, a) for line in s.replace('\r\n', '\n').replace('\r', '\n').split('\n'): if re.compile(rt).match(line): t.append(re.compile(rt).findall(line)[0]) return t """