Search code examples
pythonpyparsing

Pyparsing nested transformString


I had something working for a little while to transform a tag from lua to hmtl, but recently I got a special case where those tags could be nested. Here is a quick sample out of my code :

from pyparsing import Literal, Word, Suppress, SkipTo, LineEnd, hexnums

text = "|c71d5FFFFI'm saying something in color|cFFFFFFFF then in white |r|r"

def colorize (t):
    hexRGB = "".join(list(t.hex)[:6])
    return "<span style=\"color:#{};\">{}</span>".format(hexRGB, t.content)

vbar = Literal("|")
eol = LineEnd().suppress()

endTag = ((vbar + (Literal("r")|Literal("R"))|eol))
parser = (
    Suppress(vbar + (Literal("c")|Literal("C"))) + 
    Word(hexnums, exact=8).setResultsName("hex") + 
    SkipTo(endTag).setResultsName("content") + 
    Suppress(endTag)
).addParseAction(colorize)

result = parser.transformString(text)
print (result)

I saw an another similar question Pyparsing: nested Markdown emphasis, but my problem is a bit different, sometime there is no closetag and lineEnd is acting as one.


Solution

  • You can add a while loop to iterate over result until all the colors are found:

    from pyparsing import Literal, Word, Suppress, SkipTo, LineEnd, hexnums
    
    
    def colorize (t):
        hexRGB = "".join(list(t.hex)[:6])
        return "<span style=\"color:#{};\">{}</span>".format(hexRGB, t.content)
    
    vbar = Literal("|")
    eol = LineEnd().suppress()
    
    endTag = ((vbar + (Literal("r")|Literal("R"))|eol))
    parser = (
        Suppress(vbar + (Literal("c")|Literal("C"))) + 
        Word(hexnums, exact=8).setResultsName("hex") + 
        SkipTo(endTag).setResultsName("content") + 
        Suppress(endTag)
    ).addParseAction(colorize)
    
    result = parser.transformString(text)
    new_result = parser.transformString(result)
    
    while(result != new_result):
       result = new_result
       new_result = parser.transformString(result)
    
    
    print (result)
    

    when text = "|c71d5FFFFI'm saying something in color|cFFFFFFFF then in white |r|r":

    output:

    <span style="color:#71d5FF;">I'm saying something in color<span style="color:#FFFFFF;"> then in white</span></span>
    

    when text = "|c71d5FFFFI'm saying something in color"

    output:

    <span style="color:#71d5FF;">I'm saying something in color</span>