4

I have a regex which will convert {{ expression }} into {% print expression %} when expression is {{ function() }} or {{ object.function() }} or arithmetic operation like {{ a+b }} but will not convert when it will get {{ var }} or {{ object.attribute }}.

The issue with regex I have is it convert string expression {{ "string" }} or {{ "function()" }} or {{ "{{ var}}" }} into {% print "string" %} or {% print "function()" %} or {% print "{% print var %}" %}

import re

def replacement(val):
    content = val.group(1)
    if re.match('^\s*[\w\.]+\s*$', content):
        return "{{%s}}" % content
    else:
        return "{%% print %s %%}" % content

string_obj = """{{ var }} {{ object.var }} {{ func()}} {{ object.function() }} {{ a+b }} {{ "string" }} {{ "{{ var }}" }} {{ "function()" }} {{ "a+b" }}"""

print(re.sub("{{(\s*.*?\s*)}}", replacement, string_obj))

Output:

'{{ var }} {{ object.var }} {%print func()%} {% print object.function() %} {% print a+b %} {% print "string" %} {% print "{{ var }}" %} {% print "function()" %} {% print "a+b" %}'

The output what I want is:

'{{ var }} {{ object.var }} {%print func()%} {% print object.function() %} {% print a+b %} {{ "string" }} {{ "{{ var }}" }} {{ "function()" }} {{ "a+b" }}'

Note: The one condition here is expression in between {{ }} can have string expression like {{ "string" }} i.e. with double quotes or {{ 'string' }} i.e. with single quotes.

3
  • Presumably, this is because you're using \w in your character group. You can either add the double quotes there with \", or, don't use a regular expression and test whether "()" is in val.group(1) (and anything else like +-*/). Commented Mar 9, 2016 at 6:58
  • I can't check only "()" this because I want to convert arithmetic expression also like {{ a+b }} and if I will check "()" it will also convert the expression like {{ "function()" }}. I only want to convert {{ function () }} or {{ a+b }} not expression like {{ "function()" }} {{ "a + b" }} Commented Mar 9, 2016 at 7:10
  • Perhaps the most straightforward way is to add the cases for surrounding (double) quotes or surrounding double braces. Or find a template converter that already does what you're trying to do. Commented Mar 9, 2016 at 7:20

1 Answer 1

1

Code

For prettier printing I just strip the whitespace at beginning and end. It just simplifies the regex, too.

import re

def replacement(val):
    content = val.group(1).strip()
    if re.match('^\w[^\.\(\+\*\/\-\|]*\.?\w[^\.\(\+\*\/\-\|]*$', content):
        return "{{ %s }}" % content
    else:
        return "{%% print %s %%}" % content

def maskString(templateString):
    stringChars = ['"', "'"]
    a = 0
    start = None
    maskedList = []
    while a < len(templateString):
        l = templateString[a]
        if l in stringChars and start is None and a-1 >=0 and templateString[a-1] != '\\':
            start = {'l' : l, 's' : a}
        elif start is not None and l is start['l'] and a-1 >=0 and templateString[a-1] != '\\':
            start['e'] = a + 1
            stringToMask = templateString[start['s']:start['e']]
            templateString = templateString[:start['s']] + ("_" * len(stringToMask)) + templateString[start['e']:]
            maskedList.append(stringToMask)
            start = None
        a += 1
    return (templateString, maskedList)

def unmaskString(templateString, maskedList):
    for string in maskedList:
        templateString = templateString.replace("_" * len(string), string,1)
    return templateString

def templateMatcher(templateString):
    p = re.compile('("[^"]*)"')
    templateString, maskedList = maskString(templateString)
    templateString = re.sub("{{(\s*.*?\s*)}}", replacement, templateString)
    return unmaskString(templateString, maskedList)

string_obj = """{{ var }} {{ object.var }} {{ func()}} {{ object.function() }} {{ a+b }} {{ "string" }} {{ "{{ var }}" }} {{ "function()" }} {{ "a+b" }}"""
string_obj_2 = """{{ a+b*c-d/100}} {{ 1 * 2 }} {{ 20/10 }} {{ 5-4 }}"""
string_obj_3 = """{{ "another {{ mask" }} {{ func() }}, {{ a+b }} , {{ "string with \\""|filter }}"""

print(templateMatcher(string_obj))
print(templateMatcher(string_obj_2))
print(templateMatcher(string_obj_3))

Added an advanced masking for the strings so "\"" and '"' will be recognized as string, assuming that a variable could never consists only of _. Strings start and endcharacter are in the variable stringChars. So if you don't like the ' just remove it from there.

Output

{{ var }} {{ object.var }} {% print func() %} {% print object.function() %} {% print a+b %} {{ "string" }} {{ "{{ var }}" }} {{ "function()" }} {{ "a+b" }}
{% print a+b*c-d/100 %} {% print 1 * 2 %} {% print 20/10 %} {% print 5-4 %}
{{ "another {{ mask" }} {% print func() %}, {% print a+b %} , {% print "string with \""|filter %}
Sign up to request clarification or add additional context in comments.

9 Comments

your answer is quite right but in this pattern we can only look for the arithmetic expression which contents addition symbol. we can't parse the suibtraction, multiplication, modulo or division only {{a + b }} will be {% print a+b %} not {{ a+b*c-d/100}} or {{ 1 * 2 }} or {{ 20 - 10}} etc we also want to convert them into {% print arithmetic_operation %} unless they are not string like {{ "1 * 2" }} etc.
@yashlodha {{ a+b*c-d/100}} is in my solution converted to {% print a+b*c-d/100 %} the other like you mentioned, too. String {{ "1 * 2" }} is converted to {{ "1 * 2" }}. So where is the Problem?
{{ 1 * 2 }} into {% print 1 * 2 %} or {{ 20/10 }} into {% print 20/10%} or {{ 5-4 }} into {% print 5-4 %}.
@yashlodha updated my answer it works now with your examples. What is the grammar for the variable names? Perhaps could just replace the \w without through the grammar definition
also I have to make sure that if I have {{ "string"|filter }} it will change to {% "string"|filter %}
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.