Python создать объект среза из строки - PullRequest
7 голосов
/ 25 марта 2009

Я хотел бы создать объект среза из строки; Прямо сейчас единственный путь кажется громоздким хакерским заявлением eval

class getslice:
    def __getitem__(self, idx): return idx[0]
eval("getslice()[%s, 1]" %(":-1"))

спасибо заранее.

Редактировать : Извините, если исходное приглашение было нечетким, в этом случае ввод был ": -1". Дело было в том, чтобы разобрать строку. Ответ Игнасио Васкеса-Абрамса, по крайней мере, решил проблему (и, похоже, также работает с обратным индексированием), но я думаю, что мое решение, приведенное выше, еще более понятно, если не концептуально чисто (и будет работать правильно, если Python когда-либо изменит синтаксис срезов). 1008 *

Ответы [ 9 ]

3 голосов
/ 29 июня 2018

slice(*map(lambda x: int(x.strip()) if x.strip() else None, mystring.split(':')))

По запросу забрал его из секции комментариев.

3 голосов
/ 25 марта 2009

Если вам нужен объект среза, почему бы вам не создать его экземпляр?

s = slice(start, stop, step)

Что вы подразумеваете под "созданием его из строки"?

2 голосов
/ 27 мая 2014

Я оказался здесь, потому что хотел, чтобы мой скрипт принимал аргумент сплайсинга, похожий на python, и представлял его в виде списка целых чисел. Я сделал это с помощью функции, которая, кажется, отвечает на вопрос OP:

# create a slice object from a string
def get_slice_obj(slicearg):
    slice_ints = tuple([ int(n) for n in slicearg.split(':') ])
    return apply(slice, slice_ints)

def ints_from_slicearg(slicearg):
    slice_obj = get_slice_obj(slicearg)
    return(range(slice_obj.start or 0, slice_obj.stop or -1, slice_obj.step or 1))

for t in ['1', '1:3', '4:9:2']:
    print t, "=>", ints_from_slicearg(t)

Выход:

1 => [0]
1:3 => [1, 2]
4:9:2 => [4, 6, 8]
2 голосов
/ 25 марта 2009
slice(*[{True: lambda n: None, False: int}[x == ''](x) for x in (mystring.split(':') + ['', '', ''])[:3]])
1 голос
/ 29 января 2019

Однострочник от Игнасио Васкеса-Абрамса короткий, но трудно читаемый и обрабатывает одно число несовместимо с slice. Это пытается разобрать это более чистым способом.

def parse_slice(value):
    """
    Parses a `slice()` from string, like `start:stop:step`.
    """
    if value:
        parts = value.split(':')
        if len(parts) == 1:
            # slice(stop)
            parts = [None, parts[0]]
        # else: slice(start, stop[, step])
    else:
        # slice()
        parts = []
    return slice(*[int(p) if p else None for p in parts])
# unit tests:
try:
    assert parse_slice('')
    assert False, 'It should raise TypeError'
except TypeError:
    pass
assert parse_slice('2') == slice(2)
assert parse_slice('2:3') == slice(2, 3)
assert parse_slice(':3') == slice(None, 3)
assert parse_slice(':') == slice(None, None)
assert parse_slice('2:') == slice(2, None)
assert parse_slice('2:3:4') == slice(2, 3, 4)
assert parse_slice(':3:4') == slice(None, 3, 4)
assert parse_slice('2::4') == slice(2, None, 4)
assert parse_slice('2:3:') == slice(2, 3, None)
assert parse_slice('::4') == slice(None, None, 4)
assert parse_slice('2::') == slice(2, None, None)
assert parse_slice('::') == slice(None, None, None)
assert parse_slice('-12:-13:-14') == slice(-12, -13, -14)
assert parse_slice('2:3:-4') == slice(2, 3, -4)
try:
    parse_slice('1:2:3:4')
    assert False, 'It should raise TypeError'
except TypeError:
    pass
1 голос
/ 15 ноября 2017

Вот еще один метод (просто объединение других, размещенных здесь):

def make_slice(expr):
    def to_piece(s):
        return s and int(s) or None
    pieces = map(to_piece, expr.split(':'))
    if len(pieces) == 1:
        return slice(pieces[0], pieces[0] + 1)
    else:
        return slice(*pieces)

Пример использования:

In [1]: make_slice(':')
Out[1]: slice(None, None, None)

In [2]: make_slice(':-2')
Out[2]: slice(None, -2, None)

In [3]: x = [1, 2, 3]

In [4]: x[make_slice('::-1')]
Out[4]: [3, 2, 1]
0 голосов
/ 29 июня 2018

Как насчет этого (для простых непустых интервалов срезов):

sliceStr = "3:8"
mySlice = slice( *map(int, sliceStr.split(':') ) )
0 голосов
/ 10 августа 2017

На основе @pprzemak составлена ​​следующая функция для сложного разбора:

def parse_slice(v: Text):
    """
    Parses text like python "slice" expression (ie ``-10::2``).

    :param v:
        the slice expression or a lone integer
    :return:
        - None if input is None/empty
        - a ``slice()`` instance (even if input a lone numbrt)
    :raise ValueError:
        input non-empty but invalid syntax
    """
    orig_v = v
    v = v and v.strip()
    if not v:
        return

    try:
        if ':' not in v:
            ## A lone number given.
            v = int(v)
            return slice(v, v + 1)

        return slice(*map(lambda x: int(x.strip()) if x.strip() else None,
                          v.split(':')))
    except Exception:
        pass

    ## An alternative is to return `slice(None)` here.
    raise trt.TraitError("Syntax-error in '%s' slice!" % orig_v)
0 голосов
/ 25 марта 2009

Объект среза обычно создается с использованием индексной нотации, эта нотация использует slice () внутри, как указано в документации slice () . Что вы хотите сделать, это:

your_string[start:end]

С учебник по питону :

Строки могут быть подписаны (проиндексированы); как в C, первый символ строка имеет индекс (индекс) 0. Там не является отдельным типом символа; символ просто строка размера один. Как и в Icon, подстроки могут быть указано с обозначением среза: два индексы, разделенные двоеточием.

>>> word = 'Help' + 'A' 
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'

Индексы срезов имеют полезные значения по умолчанию; опущен первый индекс по умолчанию равен нулю, пропущенный второй индекс по умолчанию размер нарезаемой строки.

>>> word[:2]    # The first two characters
'He'
>>> word[2:]    # Everything except the first two characters
'lpA'
...