Разобрать кортеж из строки?

Скажем, у меня есть строка той же формы, что и кортеж, например, "(1,2,3,4,5)". Какой самый простой способ преобразовать это в настоящий кортеж? Пример того, что я хочу сделать:

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

Просто запуск tuple() в строке делает все это одним большим кортежем, тогда как я хотел бы понять строку как кортеж. Я знаю, что могу использовать для этого регулярное выражение, но я надеялся, что есть менее затратный способ. Идеи?


person Eli    schedule 18.03.2012    source источник
comment
Откуда струна?   -  person Karl Knechtel    schedule 19.03.2012


Ответы (4)


Он уже существует!

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

Однако помните о угловом случае:

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

Если ваш формат ввода здесь работает иначе, чем Python, вам нужно обработать этот случай отдельно или использовать другой метод, например tuple(int(x) for x in tup_string[1:-1].split(',')).

person Niklas B.    schedule 18.03.2012
comment
Удивительно, как много вопросов по SO можно решить с помощью ast.literal_eval, itertools.product и всего нескольких библиотечных функций. - person DSM; 19.03.2012
comment
@DSM: я всегда рад, если это хоть что-то интересное вроде groupby или bisect :) - person Niklas B.; 19.03.2012
comment
хороший! не знал о таком XD - person Don Question; 19.03.2012
comment
в моем случае я мог бы обработать угловой регистр для строк с помощью: not isinstance(make_tuple("('any-string')"), basestring) и дополнить вывод make_tuple дополнительной запятой, когда это необходимо. - person thadk; 27.03.2017

Я бы рекомендовал использовать literal_eval.

Если вам не нравится literal_eval или вы хотите иметь больший контроль над тем, что преобразуется, вы также можете разобрать строку, преобразовать значения и воссоздать кортеж.

Звучит сложнее, чем есть на самом деле, это однострочник:

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

Это вызовет ValueError, если какой-либо элемент (строка) в кортеже не может быть преобразован в int, например, '1.2' в строке: '(1.2, 3, 4)'.


То же самое можно сделать с помощью regex:

import re
eg = '(102,117,108)'
et_tuple = tuple(map(int, re.findall(r'[0-9]+', eg)))
person jojo    schedule 13.12.2017
comment
Поскольку вы знаете, что скобки будут на обоих концах строки, используйте strip() вместо replace(). Затем становится eg_tuple = eg.strip('()').split(',') - person R. Navega; 27.08.2018

Вы можете разобрать свою строку без SyntaxError

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

Эта функция возвращает Tuple, если синтаксический анализ прошел успешно. В противном случае вернуть None.

print parse_tuple("('A', 'B', 'C')")
person Shameem    schedule 14.06.2017

Мы также можем разобрать его самостоятельно. Допустим, у нас есть кортеж, возвращенный Python, как показано ниже:

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

Вот как мы это делаем

Во-первых, мы продолжаем читать символы в строке кортежа, но сохраняем положение последней левой точки с запятой и количество точек с запятой, которые мы встречаем (мы можем назвать это уровнем левой точки с запятой, как и для правых точек с запятой), всякий раз, когда мы встречаем правую точку с запятой, мы делаем вещи ниже:

  1. Возьмите подстроку от последней точки с запятой до текущей правой точки с запятой. (В этой подстроке больше нет точек с запятой, мы просто разбиваем ее на массив с помощью ",". Допустим, новый массив M)
  2. Затем мы добавляем M к нашему массиву результатов, который будет хранить всеM.
  3. В-третьих, удалите подстроку, которую мы взяли из исходной строки. Наконец, выполните те же действия, что и в шаге 1, пока уровень правого и левого точек с запятой не станет равным 0.

Код JavaScript выглядит следующим образом:

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;
}

person hcnak    schedule 22.08.2017