2012-03-18 20 views
38

Powiedz, że mam ciąg znaków w tej samej formie, co krotka powinna być, na przykład: "(1,2,3,4,5)". Jaki jest najprostszy sposób przekonwertowania tego na rzeczywistą krotkę? Przykładem tego, co chcę zrobić, to:Parsować krotkę z ciągu znaków?

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

Podobnie działa tuple() na strunie uczynić cały rzeczą jeden wielki krotki, natomiast to, co chciałbym zrobić, to zrozumieć ciąg jako krotki. Wiem, że mogę użyć do tego wyrażenia, ale miałem nadzieję, że jest to mniej kosztowny sposób. Pomysły?

+0

Skąd ciąg pochodzi? –

Odpowiedz

79

It already exists!

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

Bądź świadomy rogu przypadku, choć:

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

Jeśli format wejściowy działa inaczej niż Pythona tutaj, trzeba obsłużyć ten przypadek osobno lub użyć innej metody jak tuple(int(x) for x in tup_string[1:-1].split(',')).

+4

To zaskakujące, ile pytań na temat SO można uzyskać za pomocą ast.literal_eval, itertools.product i tylko garstka funkcji bibliotecznych .. – DSM

+0

@DSM: Zawsze się cieszę, jeśli jest to co najmniej coś ciekawego, np. 'Groupby' lub' bisect' :) –

+0

fajny! nie wiedziałem o tym jednym XD –

2

Można analizować swój ciąg bez SyntaxError

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

Ta funkcja zwróci Tuple jeśli parse jest sukces. W przeciwnym razie zwróć None.

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

Możemy również przeanalizować go samodzielnie. Powiedzmy mamy krotka zwrócony przez Pythonie jak poniżej:

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

Here're jak robimy to

pierwsze, zachować czytania znaków w ciąg krotki ale zapamiętuje pozycję ostatniego Lewy średnikiem i jak wiele średniki mamy spotkać (możemy nazwać lewo poziom średnik, a więc na prawo średnikami), ilekroć spotykamy prawo średnik, robimy rzeczy poniżej:

  1. Weź podciąg z ostatniego średnikiem do aktualnej prawej średnikiem. (W ten subs tring, nie ma już żadnych średników, po prostu dzielimy go na tablicę według ",". Powiedzmy, że nowa tablica to M)
  2. Następnie dodajemy M do naszej tablicy wyników, która to tablica przechowuje wszystkie M.
  3. Po trzecie, usuń podciąg pobrany z oryginalnego łańcucha. Wreszcie robić te same rzeczy jak krok 1 aż do prawej i lewej poziom średnik pochodzi 0.

kodu JavaScript jest jak poniżej:

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

bym zalecamy używanie literal_eval.

Jeśli nie są wygodne z literal_eval lub chcą mieć większą kontrolę nad tym, co zostanie przekształcone można również zdemontować ciąg, konwersja wartości i odtworzyć krotki.

Brzmi bardziej skomplikowane niż to jest, tak naprawdę, jest to jedno-liner:

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

by to rzucić ValueError jeśli każdy element (string) w krotce nie jest wymienialny na int, jak na przykład '1.2' w ciągu: '(1.2, 3, 4)'.


To samo można osiągnąć z regex:

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