Package: lexandra
LexandraCreate a lexer by decorators.How to use itimportlexandra.coreaslxdlexer:lxd.Lexer=lxd.Lexer(numbers='0123456789')@lexer.numbersdeflex_numbers(c:lxd.Cursor,s:lxd.Settings)->lxd.Token:t=lxd.Token(type='number',value=c.char)c.advance()whilec.charins.numbers:t.value+=c.charc.advance()returntif__name__=='__main__':print(lexer('123'))FactoryToo much work? Use the factory for predefined lexers.importlexandraaslxdnumbs_lexer:lxd.Lexer=lxd.factory.numbs_lexer()words_lexer:lxd.Lexer=lxd.factory.words_lexer()custom_lexer:lxd.Lexer=lxd.factory.custom_lexer(numbers='0123456789',words='qwertyuiopasdfghjklñzxcvbnm',allow_uppercase=True,ignore_space=True)if__name__=='__main__':print(numbs_lexer('123 456 789 0'))print(words_lexer('Hello World'))print(custom_lexer('Hello 123 World 456'))Cool stuffs with lexandraCreate a highlight code in the terminalimportlexandraaslxdclassColors:Black='\u001b[30m'Red='\u001b[31m'Green='\u001b[32m'Yellow='\u001b[33m'Blue='\u001b[34m'Magenta='\u001b[35m'Cyan='\u001b[36m'White='\u001b[37m'_Reset='\u001b[0m'@classmethoddefcolorize(cls,color:str,text:str)->str:returnf'{color}{text}{cls._Reset}'json_lexer:lxd.core.Lexer=lxd.factory.custom_lexer(numbers=lxd.factory.NUMBERS,letters=lxd.factory.LETTERS,strings='"',delimiters='{},:[]\n',allow_float=True,allow_uppercase=True)highlight_colors={lxd.factory.NUMB_TOKEN:Colors.Blue,lxd.factory.WORD_TOKEN:Colors.Cyan,lxd.factory.STR_TOKEN:Colors.Green,lxd.factory.DLT_TOKEN:Colors.White,}defhighlight(tokens:lxd.core.TokenList)->str:highlighted=""fortokenintokens:highlighted+=Colors.colorize(highlight_colors[token.type],token.value)returnhighlightedif__name__=='__main__':tks=json_lexer('''{"json":{"type": "array","length": 5,"items": [true, false, "lexandra", 123456789]}}''')print(highlight(tks))Why not do the same but with CSS. No new lexer is needed, just replace the ASCII Color by HTML/CSS.fromstringimportTemplateimportbase64asb64importwebbrowserimportlexandraaslxdBASE_HTML=Template(f'''<!DOCTYPE html><html><head><title>JSON Highlight</title><style>*{{white-space: pre-wrap;font-size: 30px;font-family: monospace;}}body{{background-color: #2e2e2e;border: 1px solid white;border-radius: 5px;width: fit-content;padding: 30px;margin: 0 auto;}}.token-{lxd.factory.NUMB_TOKEN}{{color: blue;}}.token-{lxd.factory.WORD_TOKEN}{{color: cyan;}}.token-{lxd.factory.STR_TOKEN}{{color: green;}}.token-{lxd.factory.DLT_TOKEN}{{color: magenta;}}</style></head><body>$content</body></html>''')json_lexer:lxd.core.Lexer=lxd.factory.custom_lexer(numbers=lxd.factory.NUMBERS,letters=lxd.factory.LETTERS,strings='"',delimiters='{},:[]\n',allow_float=True,allow_uppercase=True)defhighlight(tokens:lxd.core.TokenList)->str:content=""fortokenintokens:content+=f'<span class="token-{token.type}">{token.value}</span>'returnBASE_HTML.substitute(content=content)if__name__=='__main__':tokens=json_lexer('''{"json":{"type": "array","length": 5,"items": [true, false, "lexandra", 123456789]}}''')html=highlight(tokens).encode("utf-8")url=f'data:text/html;base64,{b64.b64encode(html).decode("utf-8")}'webbrowser.open(url)Need more decorators? Just extends!.importlexandraaslxdclassMathSettings(lxd.core.Settings):def__init__(self,numbers:str,operators:str,letters:str='',strings:str='',delimiters:str='',ignores:str='')->None:super(MathSettings,self).__init__(numbers,letters,strings,delimiters,ignores)self.__Operators=operators@propertydefoperators(self):returnself.__OperatorsclassMathLexer(lxd.core.Lexer):def__init__(self,settings:MathSettings)->None:super(MathLexer,self).__init__(settings)self.__LexOperators=None# Workaround for typing (avoid the use of generic just for keep it simple)self._Settings=settingsdefoperators(self,func:lxd.core.LexFunction):self.__LexOperators=funcdef_extended_lex(self,cursor:lxd.core.Cursor,tokens:lxd.core.TokenList)->bool:# Extending the lex conditionsifcursor.charinself._Settings.operators:tokens.append(self.__LexOperators(cursor,self._Settings))# The char is acceptablereturnTrue# The char is not acceptablereturnFalselexer:MathLexer=MathLexer(MathSettings("0123456789","+-*/",ignores=" "))@lexer.numbersdeflex_numbs(cursor:lxd.core.Cursor,settings:lxd.core.Settings)->lxd.core.Token:token=lxd.core.Token(token_type="nums",value=cursor.char)cursor.advance()whilecursor.has_charandcursor.charinsettings.numbers:token.value+=cursor.charcursor.advance()returntoken@lexer.operatorsdeflex_ops(cursor:lxd.core.Cursor,_:lxd.core.Settings)->lxd.core.Token:token=lxd.core.Token(token_type="mathop",value=cursor.char)cursor.advance()returntokenif__name__=="__main__":print(lexer("1234 + 5678 * 333 / 111 - 698"))