Pregunta

Me gustaría crear un objeto de división de una cadena; en este momento la única manera parece a través de una sentencia eval hacky engorroso

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

gracias de antemano.

Editar : Lo siento si el símbolo original no era clara, la entrada en este caso era ": -1". El objetivo era analizar la cadena. La respuesta de Ignacio Vazquez-Abrams, al menos, resolvió el problema (y parece que funciona con la indexación inversa también), pero creo que mi solución anterior es aún más clara si no es conceptualmente limpio (y funcionará correctamente si Python cambia nunca cortar la sintaxis).

¿Fue útil?

Solución

slice(*[{True: lambda n: None, False: int}[x == ''](x) for x in (mystring.split(':') + ['', '', ''])[:3]])

Otros consejos

Si desea un objeto de división, ¿por qué no se ejemplariza uno?

s = slice(start, stop, step)

¿Qué estás queriendo decir con "creándolo de una cadena"?

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

A petición, quitándola de sección de comentarios.

termino aquí porque quería que mi script para aceptar un argumento de empalme pitón similar y lo hacen en una lista de números enteros, lo hice con una función que parece que responde a la pregunta de la 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)

Salida:

1 => [0]
1:3 => [1, 2]
4:9:2 => [4, 6, 8]

Aquí hay otro método (sólo una consolidación de los demás publicada aquí):

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)

Ejemplo usos:

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]

El de una sola línea de Ignacio Vazquez-Abrams es corto pero difícilmente legible y maneja un solo número incompatible con slice. Este intenta analizar de una manera más limpia.

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

Basado en @pprzemak redactó la siguiente función para elaborado análisis:

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)

¿Qué tal esto (por intervalos rebanada vacías no simples):

sliceStr = "3:8"
mySlice = slice( *map(int, sliceStr.split(':') ) )

A objeto de división se crea normalmente usando la notación de subíndice, esta notación utiliza slice () internamente, como se indica en el rebanada () documentación. Lo que se quiere hacer es:

your_string[start:end]

la Guía de aprendizaje de :

  

Cuerdas tienen subíndices (indexados);   como en C, el primer carácter de una   cadena tiene el (índice) 0. No   se requiere ningún tipo de carácter independiente; una   personaje es simplemente una cadena de tamaño   uno. Como en Icon, las subcadenas pueden ser   especificado con la notación de rebanada: dos   índices separados por dos puntos.

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

índices Slice tienen valores predeterminados útiles; un   omitido primeros valores predeterminados de índice a cero,   Un índice segundo valor por defecto para   el tamaño de la cadena ser cortado en rodajas.

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

Mi solución a analizar estilo numpy indexación avanzada de cadena: mi GIST . Aunque se trata de una entrada antigua, que es el único que puedo encontrar en este tema. Espero que ayuda.

A sugerencia, me pega el código aquí, lo que podría ser un poco larga ... El uso del código es (suponiendo a es un objeto de matriz similar): a[parse_slice('1')] da a[1]; a[parse_slice('2:,-1')] da a[2:,-1]; etc.

import re

SLICE_TEMPLATES = [
    ('s', r'(?P<i>[+-]?\d+)'),
    ('sp', r'\((?P<i>[+-]?\d+)\)'),
    ('a', r'::?'),
    ('ri-', r'(?P<i>[+-]?\d+)::?'),
    ('ri-k', r'(?P<i>[+-]?\d+)::(?P<k>[+-]?\d+)'),
    ('r-j', r':(?P<j>[+-]?\d+):?'),
    ('r-jk', r':(?P<j>[+-]?\d+):(?P<k>[+-]?\d+)'),
    ('rij', r'(?P<i>[+-]?\d+):(?P<j>[+-]?\d+):?'),
    ('rijk', r'(?P<i>[+-]?\d+):(?P<j>[+-]?\d+):(?P<k>[+-]?\d+)'),
    ('r--k', r'::(?P<k>[+-]?\d+)'),
    ('l', r'\.\.\.'),
    ('eb', r'\[(?P<e>[+-]?\d+(,[+-]?\d+)*,?)\]'),
    ('ep', r'\((?P<e>[+-]?\d+(,[+-]?\d+)+,?)\)'),
    ('ep1', r'\((?P<e>[+-]?\d+,)\)'),
]
SLICE_TEMPLATES = [(k, re.compile(v)) for k, v in SLICE_TEMPLATES]


def tokenize_slice_groups(string):
    # tokenize groups
    groups = []
    sbuf = []
    expecting = {'(': ')', '[': ']'}
    pbbuf = []
    LEGAL_CHARS = '0123456789()[]+-:.'
    WHITESPACE_CHARS = ' \t'

    for c in string:
        if c in WHITESPACE_CHARS:
            pass
        elif c == ',':
            if len(pbbuf) not in (0, 2):
                sbuf.append(c)
            else:
                groups.append(''.join(sbuf))
                sbuf.clear()
                pbbuf.clear()
        elif c in LEGAL_CHARS:
            sbuf.append(c)
            if c in '([':
                if pbbuf:
                    raise ValueError('too many brackets in axis {}'.format(
                        len(groups)))
                pbbuf.append(c)
            elif c in ')]':
                if not pbbuf:
                    raise ValueError('brackets not match in axis {}'.format(
                        len(groups)))
                if c != expecting[pbbuf[0]]:
                    raise ValueError('brackets not match in axis {}'.format(
                        len(groups)))
                pbbuf.append(c)
        else:
            raise ValueError('illegal char `{}\''.format(c))
    groups.append(''.join(sbuf))
    return groups


def parse_slice_group(string):
    for name, tem in SLICE_TEMPLATES:
        matched = tem.fullmatch(string)
        if matched:
            if name[0] == 's':
                return int(matched.group('i'))
            if name[0] == 'a':
                return slice(None, None, None)
            if name[0] == 'r':
                i, j, k = None, None, None
                if 'i' in name:
                    i = int(matched.group('i'))
                if 'j' in name:
                    j = int(matched.group('j'))
                if 'k' in name:
                    k = int(matched.group('k'))
                return slice(i, j, k)
            if name[0] == 'l':
                return ...
            # if name[0] == 'e'
            return list(map(int, filter(None, matched.group('e').split(','))))
    raise ValueError('illegal group "{}"'.format(string))


def parse_slice(string):
    groups = tokenize_slice_groups(string)
    if groups == ['']:
        raise ValueError('index must not be empty')
    if groups and groups[-1] == '':
        del groups[-1]
    index = tuple(map(parse_slice_group, groups))
    if index.count(...) > 1:
        raise ValueError('ellipsis may occur at most once')
    return index
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top