packing things back to regular expression

Paul McGuire ptmcg at austin.rr.com
Thu Feb 21 16:29:49 EST 2008


On Feb 20, 6:29 pm, Steven D'Aprano <st... at REMOVE-THIS-
cybersource.com.au> wrote:
> On Wed, 20 Feb 2008 11:36:20 -0800, Amit Gupta wrote:
> > Before I read the message: I screwed up.
>
> > Let me write again
>
> >>> x = re.compile("CL(?P<name1>[a-z]+)")
> > # group name "name1" is attached to the match of lowercase string of
> > alphabet
> > # Now I have a dictionary saying {"name1", "iamgood"}
> > # I would like a function, that takes x and my dictionary and
> > return "CLiamgood"
> > # If my dictionary instead have {"name1", "123"}, it gives error on
> > processingit
> > #
> > # In general, I have reg-expression where every non-trivial match has a
> > group-name. I want to do the reverse of reg-exp match. The function can
> > take reg-exp and replace the group-matches from dictionary
> > # I hope, this make it clear.
>
<snip>
>
> Good luck.
>
> --
> Steven

Oh, pshaw!  Try this pyparsing ditty.

-- Paul
http://pyparsing.wikispaces.com



from pyparsing import *
import re

# replace patterns of (?P<name>xxx) with dict
# values iff value matches 'xxx' as re

LPAR,RPAR,LT,GT = map(Suppress,"()<>")
nameFlag = Suppress("?P")
rechars = printables.replace(")","").replace("(","")+" "
regex = Forward()("fld_re")
namedField = (nameFlag + \
    LT + Word(alphas,alphanums+"_")("fld_name") + GT + \
    regex )
regex << Combine(OneOrMore(Word(rechars) |
                            r"\(" | r"\)" |
                            nestedExpr(LPAR, RPAR, namedField |
regex,
                                        ignoreExpr=None ) ))

def fillRE(reString, nameDict):
    def fieldPA(tokens):
        fieldRE = tokens.fld_re
        fieldName = tokens.fld_name
        if fieldName not in nameDict:
            raise ParseFatalException(
                "name '%s' not defined in name dict" %
                (fieldName,) )
        fieldTranslation = nameDict[fieldName]
        if (re.match(fieldRE, fieldTranslation)):
            return fieldTranslation
        else:
            raise ParseFatalException(
                "value '%s' does not match re '%s'" %
                (fieldTranslation, fieldRE) )
    namedField.setParseAction(fieldPA)
    try:
        return (LPAR + namedField + RPAR).transformString(reString)
    except ParseBaseException, pe:
        return pe.msg

# tests start here
testRE = r"CL(?P<name1>[a-z]+)"

# a simple test
test1 = { "name1" : "iamgood" }
print fillRE(testRE, test1)

# harder test, including nested names (have to be careful in
# constructing the names dict)
testRE = \
    r"CL(?P<name1>[a-z]+)XY(?P<name4>(:?AB)[aeiou]+)" \
    r"(?P<name2>CD(?P<name3>..)\?EF)"
test3 = { "name1" : "iamgoodZ",
          "name2" : "CD@@?EF",
          "name3" : "@@",
          "name4" : "ABeieio",
        }
print fillRE(testRE, test3)

# test a non-conforming field
test2 = { "name1" :    "123" }
print fillRE(testRE, test2)


Prints:

CLiamgood
CLiamgoodZXYABeieioCD@@?EF
value '123' does not match re '[a-z]+'




More information about the Python-list mailing list