class AdditionalData(Exception): pass class LyricsPathUnavailable(Exception): pass class CachePathUnavailable(Exception): pass class NotFound(Exception): pass tracing=False def trace(*args,**kwargs): if not tracing: return print(*args,**kwargs) from os import path def get_file(filename): return path.join(path.dirname(__file__),filename) def processneedle(gunk,start,needle): try: start+=gunk[start:].index(needle[0])+len(needle[0]) except ValueError: trace('failed needle:',needle); return None,None end=gunk[start+1:].index(needle[1])+1 return gunk[start:start+end],start+end+len(needle[1]) def stringiter(gunk:str,needle:tuple=('',''),needles:list=[]): start=0 if needles: # Non-interactive mode. You have all the info upfront. needle=0 while True: out={} for needle in needles: res,start=processneedle(gunk,start,needle) if res==start==None: return try: out[needle[2]]=res except IndexError: try: out[''].append(res) except KeyError: out['']=[res] yield out # Interactive mode. I guess don't use this as much. if needle==('',''): needle=yield None while True: res,start=processneedle(gunk,start,needle) if res==start==None: return yield res