Python 3.x: funciones de cadena para encontrar el corchete de cierre correspondiente para cada apertura

CorePress2024-01-25  9

Tengo un problema sencillo, que espero que puedas ayudarme a resolver.

Tengo las dos listas siguientes. Abre muestra la posición de los corchetes abiertos en una consulta y cierra muestra los corchetes de cierre.

Estoy intentando combinarlos. Donde terminaré con una lista de listas.

Entrada

opens = [15, 39, 56]
closes = [44, 125, 150]

Resultado deseado:

bracket_pairs = [[39,44], [15, 150], [56, 125]]

La declaración de entrada es:

sql = '''
select * from (
select date, hour, sum(size) as x from (
select date, hour, size from database.tablename
where dt = 20210101)tbl1
group by date, hour)tbl2
'''

Así que la idea es que, para cada posición abierta, obtengamos la posición de cierre en la cadena.

Realmente no se me ocurre una forma sensata de hacer esto

¿Alguien puede ayudarme?

Esto es lo que intenté, al menos obtener los pares internos. Ahora tengo una salida donde orden = ['o', 'F', 'F', 'F', 'F', 'F', 'F', 'c'] (donde 'F' significa que los pares tienen encontrado).

Necesito decir que, para cada o, encuentre la siguiente c. este yoEs más difícil cuando tenemos esto, y la primera o debería relacionarse con la última c ['o', 'o', 'F', 'F', 'F', 'F', 'F', 'F', 'c', 'c']

query = list(sql)
opens = []
closes = []

x = 0
while x < len(query):
    if query[x] == '(':
        opens.append(x)
    elif query[x] == ')':
        closes.append(x)
    x = x+1

joined = opens + closes
joined.sort()

#joined = [15, 39, 44, 55, 65, 77, 146, 171]

order = []

for n in joined:
    if n in opens:
        order.append('o')
    elif n in closes:
        order.append('c')

#order: ['o', 'o', 'c', 'o', 'c', 'o', 'c', 'c']

couples = []
        
x = 0
while x < len(order)-1:

    next_item = x+1

    if order[x] == 'o' and order[next_item] == 'c':
        couples.append([x, next_item])
        order[x] = 'F'
        order[next_item] = 'F'
    x = x+1
    
#couples: [[1, 2], [3, 4], [5, 6]]


------------------------------------

Usando la misma lógica que la respuesta de @Durtal (es más fácil notar un corchete de cierre 'c' y emparejarlo con la 'o' abierta anterior, que encontrar una 'o' y buscar la siguiente 'c' al final profundidad de anidación adecuada); pero usando las listas que ya tienes -

Esto generará errores si algún corchete de cierre aparece antes del correspondiente abierto (por ejemplo, "abc(def)gh)ijklm(", por lo que puede manejar eso ignorando dichos corchetes de cierre; no es posible que se una parte de cualquier par.ExcLos corchetes de apertura sin errores no crearán ningún error, simplemente no llegarán a la lista final de pares:

opens = [15, 39, 56]     # These need not be sorted in any order
closes = [44, 125, 150]  # But should not contain duplicates

brackets = sorted(opens+closes)
# All bracket indices in the order as they appear

pairs = []
pending, unmatched = [], []
for pos in brackets:
    if pos in opens:
        pending.append(pos)
    else:
        try :
            pairs.append((pending.pop(-1), pos))
        except IndexError:
            unmatched.append(pos)
            continue
unmatched.extend(pending)
print(pairs, unmatched)

Si tienes que generar las listas de aperturas y cierres tú mismo, puedes usar la respuesta anterior para buscar corchetes y hacer coincidir directamente en la cadena, o agregar esto al inicio de mi código

string = input()
opens = [i for i, b in enumerate(string) if b=='(']
closes = [i for i, b in enumerate(string) if b==')']



------------------------------------

Un enfoque básico e ingenuo: cada vez que encuentres ) combínalo con la última aparición de ( que aún no tiene pareja. Detecta el error cuando había muy pocos ( hasta este punto.

sql = '''
select * from (
select date, hour, sum(size) as x from (
select date, hour, size from database.tablename
where dt = 20210101)tbl1
group by date, hour)tbl2
'''

def find_idxs_bracket(string):
    idxs_bracket_opened = []
    idxs_pairs = []
    for idx, char in enumerate(sql):
        if char == '(':
            idxs_bracket_opened.append(idx)
        if char == ')':
            try:
                idxs_pairs.append([idxs_bracket_opened[-1], idx])
                # delelte last ( from list of unmatched (
                idxs_bracket_opened = idxs_bracket_opened[:-1]
            except IndexError:
                return 'Error'
    if idxs_bracket_opened:
        return 'Error'
    return idxs_pairs

      
print(find_idxs_bracket(sql))
#[[39, 44], [56, 125], [15, 150]]

Si está interesado en lo que hay dentro de esos corchetes, podríamos preferir una solución con rexpresiones regulares.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare