2012-03-18 17 views
38

Dire che ho una stringa che è dello stesso modulo dovrebbe essere una tupla, ad esempio, "(1,2,3,4,5)". Qual è il modo più semplice per convertirlo in una vera tupla? Un esempio di quello che voglio fare è:Analizza una tupla da una stringa?

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

Proprio in esecuzione tuple() sulla corda rendere il tutto una grande tupla, mentre quello che mi piacerebbe fare è comprendere la stringa come una tupla. So che posso usare una regex per questo, ma speravo ci fosse un modo meno costoso. Idee?

+0

Da dove viene la stringa viene? –

risposta

79

E already exists!

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

essere a conoscenza di un angolo-caso, però:

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

Se il formato di input funziona diverso rispetto a Python qui, è necessario gestire quel caso separatamente o utilizzare un altro metodo come tuple(int(x) for x in tup_string[1:-1].split(',')).

+4

È sorprendente quante domande su SO possano essere risolte con ast.literal_eval, itertools.product, e solo una manciata di funzioni di libreria .. – DSM

+0

@DSM: Sono sempre contento se è almeno qualcosa di interessante come 'groupby' o' bisect' :) –

+0

bello! non sapevo di quello XD –

2

è possibile analizzare la stringa senza SyntaxError

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

Questa funzione restituisce il Tuple se parsing è successo. Altrimenti restituire None.

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

Possiamo anche analizzarlo da soli. Diciamo che abbiamo tupla restituita da Python come di seguito:

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

Here're come lo facciamo

In primo luogo, continuare a leggere i caratteri della stringa tupla ma memorizza la posizione dell'ultima virgola a sinistra e come molti punti e virgola abbiamo incontrano (possiamo chiamarla lasciato livello e virgola, come modo per punti e virgola a destra), ogni volta che ci incontriamo un punto e virgola a destra, facciamo le cose qui di seguito:

  1. Prendete una stringa da ultimo punto e virgola al corrente virgola destra. (In questo sottotitoli tring, non c'è più punto e virgola, lo abbiamo diviso in array per ",". Diciamo che il nuovo array è M)
  2. Quindi aggiungiamo M al nostro array di risultati, quale array memorizzerà tutti M.
  3. In terzo luogo, eliminare la sottostringa che abbiamo preso dalla stringa originale. Infine, fare le stesse cose, come il passaggio 1 fino a destra ea sinistra livello del punto e virgola viene a 0.

codice JavaScript è come di seguito:

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 farei consiglia di utilizzare literal_eval.

Se non si ha familiarità con literal_eval o si desidera avere maggiore controllo su ciò che viene convertito è anche possibile smontare la stringa, convertire i valori e ricreare la tupla.

suoni più complicato di quello che è, in realtà, si tratta di una battuta:

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

Ciò gettare un ValueError se ogni elemento (stringa) nella tupla non è convertibile in int, come, ad esempio, il '1.2' nella stringa: '(1.2, 3, 4)'.


Lo stesso può essere realizzato con regex:

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