'Syntax highlight python

I want to make a simple python highlighter for a homework, but things like comments or strings are not being colored, I'm supposed to use regular expressions for the homework (regex).

import re

#Expresiones regulares de regEX
palabrasRe= re.compile(r'\b(False|class|return|None|continue|lambda|try|True|def|nonlocal|while|for|and|del|not|with|as|elif|or|yield|assert|if|else|pass|break|except|raise|list|print|from|import|except|finally|raise|global|in|is|del|with|as|async|await)')
string1 = re.compile(r'[\'][\W\w]*[\']')
string2 = re.compile(r'[\"][\W\w]*[\"]')
comentario1 = re.compile(r'#.+\n')
comentario2 = re.compile(r'(\'{3}(.+\n)*\'{3})')
num = re.compile(r'(\d+(?:\.\d+)?)')
identificador = re.compile(r'\b[a-zA-z]\w*')
operadores= re.compile(r'(\+|\-|\/|\*|\%|\>|\<|\=)')
caractEspeciales = re.compile(r'\W')

#Abrir el archivo para leer 
archivo = open('ej.py', "r")
lineas = archivo.readlines()
archivo.close()

#Archivo de html
html = open('holamundo.html','w')
mensaje = " "


#Listas para las coordenadas 
pos_ren=0
copalRev=[]
costr1=[]
costr2=[]
cocomen1=[]
cocomen2=[]
conum=[]
coiden=[]
coop=[]
corcarE=[]

#Leer elementos del archivo para revisarlos
for i in lineas:
    ren=lineas[pos_ren]
    
    menren=ren
    mensaje+="<p>"
    
    search = operadores.finditer(menren)
    for match in search:
        cor=match.span()
        coop.append(cor)
        #print(match)
 
    search = identificador.finditer(menren)
    for match in search:
        cor=match.span()
        coiden.append(cor)
        #print(match)
    
        
    search = num.finditer(menren)
    for match in search:
        cor=match.span()
        conum.append(cor)
        #print(match)

    search = palabrasRe.finditer(menren)
    for match in search:
        cor=match.span()
        copalRev.append(cor)
        #print(match)

    search = string2.finditer(menren)
    for match in search:
        cor=match.span()
        costr2.append(cor)

    search = string1.finditer(menren)
    for match in search:
        cor=match.span()
        costr1.append(cor)

    search = comentario1.finditer(menren)
    for match in search:
        cor=match.span()
        cocomen1.append(cor)

    search = comentario2.finditer(menren)
    for match in search:
        cor=match.span()
        cocomen2.append(cor)

    search = caractEspeciales.finditer(menren)
    for match in search:
        cor=match.span()
        corcarE.append(cor)

    for i in coop:
     x,y=i
     print(i)
     print(ren)
     pal=ren[x:y]
     
     mensaje2="<FONT COLOR='#FFA500'>"+pal+"</FONT>"  # COLOR OPERADORES
     menren= menren.replace(pal, mensaje2)
     #ren[x:y]= mensaje2
    coop=[]
    
    for i in coiden:
     x,y=i
     print(i)
     pal=ren[x:y]
     print(pal)
     mensaje4="<FONT COLOR='#5982D3'>"+pal+"</FONT>"    # COLOR IDENTIFICADORES
     menren= menren.replace(pal, mensaje4)
     #ren[x:y]= mensaje3
    coiden=[]
    
    for i in conum:
     x,y=i
     print(i)
     pal=ren[x:y]
     print(pal)
     mensaje5="<FONT COLOR='#8032E4'>"+pal+"</FONT>"   # COLOR NUMEROS
     menren= menren.replace(pal, mensaje5)
     #ren[x:y]= mensaje3
    conum=[]

    for i in copalRev:
     x,y=i
     print(i)
     pal=ren[x:y]
     print(pal)
     mensaje6="<FONT COLOR='#FFCE3O'>"+pal+"</FONT>"   # COLOR PALABRAS RESERVADAS
     menren= menren.replace(pal, mensaje6)
     #ren[x:y]= mensaje3
    copalRev=[]

    for i in cocomen1:
     x,y=i
     print(i)
     pal=ren[x:y]
     print(pal)
     mensaje7="<FONT COLOR='#FFFFFF'>"+pal+"</FONT>"   # COLOR PALABRAS RESERVADAS
     menren= menren.replace(pal, mensaje7)
     #ren[x:y]= mensaje3
    cocomen1=[]

    for i in costr1:
     x,y=i
     print(i)
     pal=ren[x:y]
     print(pal)
     mensaje8="<FONT COLOR='#FFFFFF'>"+pal+"</FONT>"   # COLOR PALABRAS RESERVADAS
     menren= menren.replace(pal, mensaje8)
     #ren[x:y]= mensaje3
    costr1=[]

    mensaje+=menren+"</p>"    
    pos_ren+=1



html.write("<html><head></head><body bgcolor='#232231' >"+mensaje+"</body></html>")
html.close()

It should be coloring reserved words, both types of strings, both type of comments, numbers, identifiers, operators and special characters. So far I'm getting this: Current highlight process



Solution 1:[1]

I tried to refactor this to stop all of your manual copy/pasting with loops... but I'm too tired to debug why it's not running now. Here's how far I got.

import re
from collections import defaultdict

# Expresiones regulares de regEX
KEYWORDS = [
    'False', 'class', 'return', 'None', 'continue', 'lambda', 'try', 'True', 'def', 'nonlocal', 'while', 'for', 'and',
    'del', 'not', 'with', 'as', 'elif', 'or', 'yield', 'assert', 'if', 'else', 'pass', 'break', 'except', 'raise',
    'list', 'print', 'from', 'import', 'except', 'finally', 'raise', 'global', 'in', 'is', 'del', 'with', 'as',
    'async', 'await',
]

REGEXES = {
    'palabrasRe': re.compile(fr'\b({"|".join(KEYWORDS)})'),
    'string1': re.compile(r'[\'][\W\w]*[\']'),
    'string2': re.compile(r'[\"][\W\w]*[\"]'),
    'comentario1': re.compile(r'#.+\n'),
    'comentario2': re.compile(r'(\'{3}(.+\n)*\'{3})'),
    'num': re.compile(r'(\d+(?:\.\d+)?)'),
    'identificador': re.compile(r'\b[a-zA-z]\w*'),
    'operadores': re.compile(r'(\+|\-|\/|\*|\%|\>|\<|\=)'),
    'caractEspeciales': re.compile(r'\W'),
}

COORDS_TRANSLATION = {
    'palabrasRe': 'copalRev',
    'string1': 'costr1',
    'string2': 'costr2',
    'comentario1': 'cocomen1',
    'comentario2': 'cocomen2',
    'num': 'conum',
    'identificador': 'coiden',
    'operadores': 'coop',
    'caractEspeciales': 'corcarE',
}

COLORS = {
    'copalRev': '#FFCE3O',
    'costr1': '#FFFFFF',
    'costr2': '#',
    'cocomen1': '#FFFFFF',
    'cocomen2': '#',
    'conum': '#8032E4',
    'coiden': '#5982D3',
    'coop': '#FFA500',
    'corcarE': '#',
}

# Abrir el archivo para leer
with open('scratch_2.py', "r") as archivo:
    lineas = archivo.readlines()

# Archivo de html
html = open('holamundo.html', 'w')
mensaje = " "

# Listas para las coordenadas
# Lists for the coordinates
pos_ren = 0
coordinates = defaultdict(list)

# Leer elementos del archivo para revisarlos
for i in lineas:
    ren = lineas[pos_ren]

    menren = ren
    mensaje += "<p>"

    for name, regex in REGEXES.items():

        search = REGEXES[name].finditer(menren)
        for match in search:
            cor = match.span()
            coordinates[COORDS_TRANSLATION[name]].append(cor)

    for name2, color in COLORS.items():
        for j in coordinates[name2]:
            x, y = j
            print(j)
            print(ren)
            pal = ren[x:y]

            mensaje = f"<FONT COLOR='#{color}'>{pal}</FONT>"  # COLOR OPERADORES
            menren = menren.replace(pal, mensaje)

        coordinates[name2].clear()

        mensaje += menren + "</p>"
        pos_ren += 1

html.write(f"<html><head></head><body bgcolor='#232231' >{mensaje}</body></html>")
html.close()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1