pitón crear objeto de división de la cadena de
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).
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]
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