ColourText . ![alt text](http://25.media.tumblr.com/tumblr_lxlteprWtD1r26npvo1_500.png) **Purpose**. This is a simple pattern that shows how to output colour in a console. If you run the tool, you can see test cases run, much like in the screenshot above this post. **Usage**. To get blue text like you see in the example, you'd create an object called cstring like this: ```python ob = ColourText.cstring("This has |blue:blue* text") ``` Then render it: ```python ColourText.to_ascii(ob) ``` **Code.** ```python #!/usr/bin/python # # Provides a mechanism for creating text with arbitrary formatting. # # Example # # raw = "|red:this text comes out red* Now we're outside of formatting" # ob = cstring(raw) # print to_ascii(ob) # # Backslash acts as an escape character. # # There's a simple to_ascii function further down that returns a stream # of symbols that will render to colour in ascii, and there's test # cases at the end showing more examples # # cturner, 20101121 # class cstring(object): """Colour string. Star marks end of a block. Example: "Text |red:I am red|blue:I'm blue* This bit has no formatting".""" # Indicates a string MARKER_S = 's' # Indicates start of a format block MARKER_F = 'f' # Indicates end of a format block MARKER_X = 'x' def __init__(self, text): (self._sequence, self._length) = self._parse(text) def _parse(self, text): """Returns a sequence of segments, and a length.""" cb = [] wb = [] _str = 0 _tag = 1 _str = 2 b_escape = False state = _str length = 0 for c in text: if b_escape: wb.append(c) else: if state == _str: if c == '|': length += len(wb) cb.append( (self.MARKER_S, ''.join(wb)) ) wb = [] state = _tag elif c == '*': length += len(wb) cb.append( (self.MARKER_S, ''.join(wb)) ) cb.append( (self.MARKER_X, '') ) wb = [] else: wb.append(c) else: if c == ':': format_option = ''.join(wb) cb.append( (self.MARKER_F, format_option) ) wb = [] state = _str else: wb.append(c) if state != _str: er = ' '.join( [ "Invalid format string. Still in format option" , "at end of string. '%s'"%(''.join(wb)) ] ) raise Exception(er) if 0 < len(wb): length += len(wb) cb.append( (self.MARKER_S, ''.join(wb)) ) if not cb[-1][0] == self.MARKER_X: cb.append( (self.MARKER_X, '') ) return (cb, length) def __iter__(self): return (x for x in self._sequence) def __len__(self): return self._length class CstringException(Exception): def __init__(self, msg): self.message = msg # -------------------------------------------------------- # struct # -------------------------------------------------------- COLOURS = { 'blue': '\033[94m' , 'green': '\033[92m' , 'yellow': '\033[93m' , 'red': '\033[91m' } ENDC = '\033[0m' def to_ascii(cs): sb = [] for code, value in cs: if code == 's': sb.append(value) elif code == 'f': if value in COLOURS: sb.append(COLOURS[value]) else: er = "Don't have a handler for format option '%s'"%value raise Exception(er) elif code == 'x': sb.append(ENDC) sb.append(value) else: raise Exception("cstring is invalid stream. got code %s."%code) return ''.join(sb) # -------------------------------------------------------- # test # -------------------------------------------------------- def test(): lst_test_string = [ "This is simple text." , u"This is simple text, but unicode" , "This has |blue:blue* text" , u"Unicode |green:green |red:and red* text" , "|yellow:neglect to close tap here" , '' , "That last line was empty deliberately" ] for c in COLOURS: lst_test_string.append("|%s:%s*"%(c, c)) for s in lst_test_string: print "> %s"%s cs = cstring(s) #print cs.sequence print 'length', len(cs) print to_ascii(cs) #print # -------------------------------------------------------- # loader # -------------------------------------------------------- if __name__ == '__main__': test() ```