2

I have a nested expression as below

 expression = 'position(\'a\' IN Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ,  "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))'

I want the output as by retreiving nested function first and then outer functions

['Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ,  "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" )','position(\'a\' IN Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ,  "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))']

Below is the code I have tried

 result = []
 for i in range(len(expression)):
     if expression[i]=="(":
        a.append(i)
     elif expression[i]==")":
          fromIdx=a.pop()
          fromIdx2=max(a[-1],expression.rfind(",", 0, fromIdx))
          flag=False
          for (fromIndex, toIndex) in first_Index:
             if fromIdx2 + 1 >= fromIndex and i <= toIndex:
                 flag=True
                 break
          if flag==False:
             result.append(expression[fromIdx2+1:i+1])

But this works only if expression is separated by ',' for ex:

expression = 'position(\'a\' , Concat("function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ,  "function_test"."PRODUCT_CATEGORIES"."CATEGORY_NAME" ))'

and result for this expression from my code will be correct as exprected. In first expression ,I mentioned ,there is IN operator instead of ',' hence my code doesnt work.

Please help

2
  • pls format this. Commented Mar 1, 2021 at 13:59
  • @leoOrion have formatted properly now.Please check Commented Mar 1, 2021 at 14:29

1 Answer 1

2

If you want it to be reliable, you need a full-fledged SQL parser. Fortunately, there is an out-of-box solution for that: https://pypi.org/project/sqlparse/. As soon as you have a parsed token tree, you can walk through it and do what you need:

import sqlparse

def extract_functions(tree):
    res = []
    def visit(token):
        if token.is_group:
            for child in token.tokens:
                visit(child)
        if isinstance(token, sqlparse.sql.Function):
            res.append(token.value)
    visit(tree)
    return res

extract_functions(sqlparse.parse(expression)[0])

Explanation. sqlparse.parse(expression) parses the string and returns a tuple of statements. As there is only one statement in the example, we can just take the first element. If there are many statements, you should rather iterate over all tuple elements.

extract_functions recursively walks over a parsed token tree depth first (since you want inner calls appear before outer ones) using token.is_group to determine if the current token is a leaf, tests if the current token is a function, and if it is, appends its string representation (token.value) to the result list.

Sign up to request clarification or add additional context in comments.

6 Comments

Thankyou for the answer.will it work for any kind of complex expressions and return the nested functions starting from innermost. And is it feasible to use the package sqlparse?Any disadvantage of using sqlparse?
It should work unless there are bugs in the parser. I don't know what may be disadvantages. May be if you have some very special restrictions on using third-party packages, this may cause troubles. But in general case it should be perfectly OK. It is one of the coolest things in Python, that you can find an out-of-box package virtually for everything.
okay thankyou.Can you please explain me this code.
Added an explanation.
Have found one issue in this code recently saying it will not support spaces after function name example upper (name) will not work.Can you please help me with this
|

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.