2012-03-18 11 views
38

Supongamos que tengo una cadena que tiene la misma forma que una tupla, por ejemplo, "(1,2,3,4,5)". ¿Cuál es la forma más fácil de convertir eso en una tupla real? Un ejemplo de lo que quiero hacer es:Parse a tuple from a string?

tup_string = "(1,2,3,4,5)" 
tup = make_tuple(tup_string) 

Sólo corriendo tuple() en la cadena hacen que la cosa entera de una gran tupla, mientras que lo que me gustaría hacer es comprender la cadena como una tupla. Sé que puedo usar una expresión regular para esto, pero esperaba que fuera una forma menos costosa. Ideas?

+0

¿De dónde viene la cadena viene? –

Respuesta

79

¡Es already exists!

>>> from ast import literal_eval as make_tuple 
>>> make_tuple("(1,2,3,4,5)") 
(1, 2, 3, 4, 5) 

ser consciente de la esquina de los casos, sin embargo:

>>> make_tuple("(1)") 
1 
>>> make_tuple("(1,)") 
(1,) 

Si su formato de entrada diferente que funciona Python aquí, es necesario gestionar el caso por separado o utilizar otro método como tuple(int(x) for x in tup_string[1:-1].split(',')).

+4

Es sorprendente cuántas preguntas sobre SO pueden responderse con ast.literal_eval, itertools.product y solo un puñado de funciones de la biblioteca. – DSM

+0

@DSM: Siempre me alegra si es al menos algo interesante como 'groupby' o' bisect' :) –

+0

¡lindo! no sabía acerca de eso XD –

2

puede analizar su cadena sin SyntaxError

def parse_tuple(string): 
    try: 
     s = eval(string) 
     if type(s) == tuple: 
      return s 
     return 
    except: 
     return 

Esta función devuelve el Tuple si de análisis es el éxito. De lo contrario, devuelva None.

print parse_tuple("('A', 'B', 'C')") 
0

También podemos analizarlo por nosotros mismos. Digamos que hemos tupla devuelta por Python, como a continuación:

((2, 'C/C++', 0, 'clang_cpp'), (3, 'Python相关', 0, 'python')) 

Acá cómo lo hacemos

En primer lugar, mantener la lectura de los caracteres de la cadena tupla pero almacena la posición del último punto y coma izquierda y cómo muchos puntos y comas que tienen reúnen (podemos llamarlo dejó nivel de punto y coma, como así por punto y coma derecha), cada vez que nos encontramos con un punto y coma bien, hacemos las cosas a continuación:

  1. Tome una subcadena de última coma a coma derecho actual. (En este subs tring, no hay más puntos y comas, simplemente lo dividimos en array por ",". Digamos que la nueva matriz es M)
  2. Luego agregamos M a nuestra matriz de resultados, que matriz almacenará todos M.
  3. En tercer lugar, elimine la subcadena que tomamos de la cadena original. Por último, hacer las mismas cosas como el paso 1 hasta que la derecha y la izquierda nivel de punto y coma llega a 0.

código JavaScript es como abajo:

function parseTuple(t){ 
 
    var lc = "("; 
 
    var rc = ")"; 
 
    var lc_level = 0; 
 
    var rc_level = 0; 
 
    var last_lc = 0; 
 
    var last_rc = 0; 
 
    var result = []; 
 
    for(i=0;i<t.length;i++){ 
 
     if(t[i] == lc){ 
 
      lc_level++; 
 
      last_lc = i; 
 
     }else if(t[i] == rc){ 
 
      rc_level++; 
 
      last_rc = i; 
 
     } 
 
     if(rc_level == 1){ 
 
      var substr = t.slice(last_lc+1,last_rc); 
 
      var data = substr.split(","); 
 
      result.push(data); 
 
      lc_level--; 
 
      rc_level--; 
 
      i = 0; 
 
      t = t.slice(0,last_lc) + t.substring(last_rc+1); 
 
     } 
 
     if(lc_level == rc_level && lc_level==0){ 
 
      break; 
 
     } 
 
    } 
 
    return result; 
 
}

1

lo haría recomendamos usar literal_eval.

Si no se siente cómodo con literal_eval o desea tener más control sobre lo que se convierte también se puede desmontar la cadena, convertir los valores y volver a crear la tupla.

suena más complicado de lo que es, en realidad, se trata de una sola línea:

eg = '(102,117,108)' 
eg_tuple = map(int, eg.replace('(','').replace(')','').split(','))) 

Esto sería lanzar una ValueError si cualquier elemento (cadena) en la tupla no se puede convertir en int, como, por ejemplo, '1.2' en la cadena: '(1.2, 3, 4)'.


El mismo se puede conseguir con regex:

import re 
eg = '(102,117,108)' 
et_tuple = tuple(map(int, re.findall(r'[0-9]+', eg)))