Python中可能嵌套的函数表达式的拆分列表

时间:2012-10-16 21:31:09

标签: python list split

PostgreSQL允许在表达式上创建索引,例如CREATE INDEX ON films ((lower(title)))。它还具有pg_get_expr()信息功能,可将表达式的内部格式转换为文本,即前一个示例中的lower(title)。这些表达式有时会非常毛茸茸。以下是一些示例(在Python中):

sample_exprs = [
    'lower(c2)',
    'lower(c2), lower(c3)',
    "btrim(c3, 'x'::text), lower(c2)",
    "date_part('month'::text, dt), date_part('day'::text, dt)",
    '"substring"(c2, "position"(c2, \'_begin\'::text)), "substring"(c2, "position"(c2, \'_end\'::text))',
    "(((c2)::text || ', '::text) || c3), ((c3 || ' '::text) || (c2)::text)",
    'f1(f2(arga, f3()), arg1), f4(arg2, f5(argb, argc)), f6(arg3)']

最后一项不是来自Postgres,而只是我的代码应该处理的一个极端例子。

我编写了一个Python函数来将文本列表拆分为组件表达式。例如,最后一项分为:

 f1(f2(arga, f3()), arg1)
 f4(arg2, f5(argb, argc))
 f6(arg3)

我尝试了str方法,例如find()count(),并且还考虑了正则表达式,但最后我写了一个函数,这是我用C语言编写的(基本上是计算开放的)并关闭parens以找到打破文本的位置)。这是功能:

def split_exprs(idx_exprs):
    keyexprs = []
    nopen = nclose = beg = curr = 0
    for c in idx_exprs:
        curr += 1
        if c == '(':
            nopen += 1
        elif c == ')':
            nclose += 1
            if nopen > 0 and nopen == nclose:
                if idx_exprs[beg] == ',':
                    beg += 1
                if idx_exprs[beg] == ' ':
                    beg += 1
                keyexprs.append(idx_exprs[beg:curr])
                beg = curr
                nopen = nclose = 0
    return keyexprs

问题在于是否有更多的Pythonic或优雅方式来执行此操作或使用正则表达式来解决此问题。

2 个答案:

答案 0 :(得分:1)

如果你想让它更加pythonic,我能想到的唯一方法就是可读性。

另外,我通过计算堆栈来避免一个分支和一个变量。我能给出的唯一的pythonic建议是使用带有enumerate(...)函数的'index'变量。如在

for i, j in enumerate(<iterable>)

这将创建一个变量i,它将等于当前循环数,其中j将是预期的迭代变量。

def split_fns(fns):
    paren_stack_level = 0
    last_pos = 0
    output = []
    for curr_pos, curr_char in enumerate(fns):
        if curr_char == "(":
            paren_stack_level += 1
        elif curr_char == ")":
            paren_stack_level -= 1
            if not paren_stack_level:
                output.append( fns[last_pos:curr_pos+1].lstrip(" ,") )
                last_pos = curr_pos+1
    return output

for i in sample_exprs:
    print(split_fns(i))

答案 1 :(得分:1)

这是我的版本,更多的pythonic,更少的混乱,我认为,并在chars流上工作,虽然我没有看到任何优势:)

def split_fns(fns):
    level = 0
    stack = [[]]
    for ch in fns:
        if level == 0 and ch in [' ',',']:
            continue        
        stack[-1].append(ch)

        if ch == "(":
            level += 1
        elif ch == ")":
            level -= 1
            if level == 0:
                stack.append([])

    return ["".join(t) for t in stack if t]