处理使用递归函数构建字符串

时间:2016-12-07 04:49:36

标签: python python-3.x recursion

我有一个打印字符串的递归函数。 我希望函数返回当前打印的字符串。

代码基本上打印出不同级别的递归所需的字符串的不同部分。

我正在考虑使用全局变量,但并不认为这听起来非常pythonic。

作为更大程序的一部分,我将多次调用此函数。

如果您想查看当前的代码:

def check_if_multiple_sections(the_string):
    level = 0
    counter = 0
    for char in the_string:
        if char == '(':
            level = level + 1
            if level == 0:
                counter = counter + 1
        if char == ')':
            level = level - 1
            if level == 0:
                counter = counter + 1
    return counter

def break_it_up(the_string):
    level = 0
    counter = 0
    break_points = []
    for char in the_string:
        if char == '(':
            level = level + 1
        if char == ')':
            level = level - 1
            if level == 0:
                break_points.append(counter + 1)
        counter = counter + 1
    return break_points


def recur_markov_change(the_string, key):
    #print("the_string: " + str(the_string) + " : key: " +str(key))
    if key is not None:
        #print(the_string)
        #print("YEA")
        print(str(the_string).split(' ')[0] +'^'+str(key) + ' ', end='')
    else:
        print('(TOP ', end ='')
    key = ((the_string.split(' '))[0])[1:]

    if len(the_string) < 2:
        return
    remaining_string = the_string.split(' ', 1)[1][:-1]
    results = []
    results.append(((remaining_string.split(' '))[0])[1:])
    level = 0
    counter = 0
    if the_string.count('(') == 1:
        items = the_string[1:-1]
        both = items.split(' ')
        print(str(the_string).split(' ',1)[1], end="") #This prints leaves
        return

    for char in remaining_string:
        if char == '(':
            level = level + 1
        if char == ')':
            level = level - 1
        if level == 0 and char == ' ':
            results.append(((remaining_string[counter+1:].split(' '))[0])[1:])
        counter = counter + 1
    answer = (key, results, remaining_string)
    #print(answer)

    if check_if_multiple_sections(remaining_string) > 1:
        break_points = break_it_up(remaining_string)
        sublines = []
        prev_spot = 0
        for breaks in break_points:
            sublines.append(remaining_string[prev_spot:breaks].strip())
            prev_spot = breaks
        sublines.append(remaining_string[breaks:].strip())
        for line in sublines:
            if len(line) > 2:
                print(' ', end='')
                recur_markov_change(line, key)
    print(')', end='')


given_string = '(TOP (SBARQ (WHNP_WDT  Which) (SQ_VP (VBZ  is) (ADJP_JJ  last))) (PUNC  ?))'
string_that_I_want_function_to_return = '(TOP (SBARQ^TOP (WHNP_WDT^SBARQ  Which) (SQ_VP^SBARQ (VBZ^SQ_VP  is) (ADJP_JJ^SQ_VP  last))) (PUNC^TOP  ?))'

recur_markov_change(given_string, None)
print("\ndesired string:")
print(string_that_I_want_function_to_return)

2 个答案:

答案 0 :(得分:2)

首先,我添加了一个函数递归添加的基本字符串。我调用了此initial,然后我用inititial+=替换了所有打印件,最后返回initial

def check_if_multiple_sections(the_string):
    level = 0
    counter = 0
    for char in the_string:
        if char == '(':
            level = level + 1
            if level == 0:
                counter = counter + 1
        if char == ')':
            level = level - 1
            if level == 0:
                counter = counter + 1
    return counter

def break_it_up(the_string):
    level = 0
    counter = 0
    break_points = []
    for char in the_string:
        if char == '(':
            level = level + 1
        if char == ')':
            level = level - 1
            if level == 0:
                break_points.append(counter + 1)
        counter = counter + 1
    return break_points


def recur_markov_change(the_string, key, initial):
    #initial+=("the_string: " + str(the_string) + " : key: " +str(key))
    if key is not None:
        #initial+=(the_string)
        #initial+=("YEA")
        initial+=(str(the_string).split(' ')[0] +'^'+str(key) + ' ')
    else:
        initial+=('(TOP ')
    key = ((the_string.split(' '))[0])[1:]

    if len(the_string) < 2:
        return
    remaining_string = the_string.split(' ', 1)[1][:-1]
    results = []
    results.append(((remaining_string.split(' '))[0])[1:])
    level = 0
    counter = 0
    if the_string.count('(') == 1:
        items = the_string[1:-1]
        both = items.split(' ')
        initial+=(str(the_string).split(' ',1)[1]) #This initial+=s leaves
        return initial

    for char in remaining_string:
        if char == '(':
            level = level + 1
        if char == ')':
            level = level - 1
        if level == 0 and char == ' ':
            results.append(((remaining_string[counter+1:].split(' '))[0])[1:])
        counter = counter + 1
    answer = (key, results, remaining_string)
    #initial+=(answer)

    if check_if_multiple_sections(remaining_string) > 1:
        break_points = break_it_up(remaining_string)
        sublines = []
        prev_spot = 0
        for breaks in break_points:
            sublines.append(remaining_string[prev_spot:breaks].strip())
            prev_spot = breaks
        sublines.append(remaining_string[breaks:].strip())
        for line in sublines:
            if len(line) > 2:
                initial+=(' ')
                initial = recur_markov_change(line, key, initial)
    initial+=(')')
    return initial


given_string = '(TOP (SBARQ (WHNP_WDT  Which) (SQ_VP (VBZ  is) (ADJP_JJ  last))) (PUNC  ?))'
string_that_I_want_function_to_return = '(TOP (SBARQ^TOP (WHNP_WDT^SBARQ  Which) (SQ_VP^SBARQ (VBZ^SQ_VP  is) (ADJP_JJ^SQ_VP  last))) (PUNC^TOP  ?))'

print(recur_markov_change(given_string, None, ""))
print("\ndesired string:")
print(string_that_I_want_function_to_return)

经过测试和工作,就像我的魅力一样

答案 1 :(得分:0)

...This would be impossible without recursion.., - 没有递归就有可能。

import collectons, operator
s = '(TOP (SBARQ (WHNP_WDT  Which) (SQ_VP (VBZ  is) (ADJP_JJ  last))) (PUNC  ?))'
result = '(TOP (SBARQ^TOP (WHNP_WDT^SBARQ  Which) (SQ_VP^SBARQ (VBZ^SQ_VP  is) (ADJP_JJ^SQ_VP  last))) (PUNC^TOP  ?))'

我将使用自定义Node方法的类___str___。节点的有效负载将是其他节点或最内层节点的字符串。

class Node:
    def __init__(self, name, index):
        self.name = name
        self.index = index
        self.parent = None
        self._payload = []
    @property
    def payload(self):
        return self._payload
    @payload.setter
    def payload(self, thing):
        self._payload.append(thing)
    def __str__(self):
        if self.parent is not None:
            name = '{}^{}'.format(self.name, self.parent.name)
        else:
            name = self.name
        #account for the extra space in a non-Node paylode
        if not isinstance(self.payload[0], Node):
            payload = ' ' + self.payload[0]
        else:
            payload = ' '.join(str(thing) for thing in self.payload)
        return '({!s:} {!s:})'.format(name, payload)

该函数首先找到所有左右parens的索引。如果左边的paren后跟左边的paren,则会创建未完成的节点。 当找到左/右paren对时,节点已被完全解析(完成)。它返回最外层的节点。

def parse(s):
    # Where are the parenthesis?
    unfinished_nodes = collections.deque()
    left, right = collections.deque(), collections.deque()
    for i, c in enumerate(s):
        if c == '(':
            left.append(i)
        if c == ')':
            right.append(i)

    if len(left) != len(right):
        raise ValueError('Unbalanced parenthesis in s')

    # helpers
    paren = operator.itemgetter(0)
    next_paren = operator.itemgetter(1)

    while left and right:
        while paren(left) > paren(right):
            # back-up to previous Node
            left.rotate()
        #print('left:{}, right:{}'.format(paren(left), paren(right)))
        # are we at the bottom? No more Nodes?
        try:
            if next_paren(left) < paren(left):
                finished = True
            else:
                finished = paren(left) < paren(right) < next_paren(left)
        except IndexError:
            # only one more left paren - outermost Node
            finished = True
        if finished:
            token = s[paren(left)+1:paren(right)]
            #print('\ttoken:{}'.format(token))
            if '(' not in token:
                # this is an inner Node
                name, payload = token.split()
                node = Node(name, paren(left))
                node.payload = payload
                try:
                    node.parent = unfinished_nodes[-1]
                    node.parent.payload = node
                except IndexError:
                    # this inner Node is the first Node in the sequence
                    pass
                unfinished_nodes.append(node)
            # finished is the outermost completely parsed node
            finished = unfinished_nodes.pop()
            #print('\tfinished:{!s:}'.format(finished.name))
            right.popleft()
            left.popleft()
            #print('\t\tL:{}\t\tR:{}'.format(left, right))
        else:
            name = s[paren(left)+1:next_paren(left)]
            name = name.strip()
            node = Node(name, paren(left))
            try:
                node.parent = unfinished_nodes[-1]
                node.parent.payload = node
            except IndexError:
                # this is the outermost Node
                pass
            #print('\tnew Unfinished:{}'.format(node.name))
            unfinished_nodes.append(node)
            # proceed to the next Node
            left.rotate(-1)
    return finished
    #or if you prefer
    #return str(finished)

print(parse(s))
print(result)

这里简化了,没有任何恶作剧,非递归,一次通过输入字符串 - 快速,干净,高效:

import collections
def parse2(s):
    parents = collections.deque()
    final = collections.deque()
    t = ''
    new_parent = False
    new = ''
    for c in s:
        if c == '(':
            new_parent = True
            t += c
        elif c == ')':
            t += c
            final.append(t)
            t = ''
            parents.pop()
        else:
            if c == ' ' and new_parent:
                if parents:
                    t = t + '^' + parents[-1]
                parents.append(new)
                new_parent = False
                new = ''
            elif new_parent:
                new += c
            t += c
    return ''.join(final)

不确定是什么让我使用Node类来提出第一个解决方案,并将其视为树/图形/其他。