Frage

Ich möchte ein Stück Objekt aus einem String erstellen; Im Augenblick ist die einzige Möglichkeit, eine umständliche Hacky eval Aussage scheint durch

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

Vielen Dank im Voraus.

Bearbeiten : Sorry, wenn die ursprüngliche Aufforderung nicht klar war, der Eingang war in diesem Fall ": -1". Der Punkt war die Zeichenfolge zu analysieren. Ignacio Vazquez-Abrams Antwort zumindest das Problem gelöst (und scheint mit Reverse-Indizierung als gut zu funktionieren), aber ich denke, dass meine Lösung oben ist noch unklar, ob nicht begrifflich sauber (und funktioniert einwandfrei, wenn Python jemals ändert Syntax Slicing).

War es hilfreich?

Lösung

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

Andere Tipps

Wenn Sie ein Segmentobjekt wollen, warum Sie nicht nur ein instanziiert?

s = slice(start, stop, step)

Was bedeutet, dass Sie durch „es aus einem String zu schaffen“?

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

Auf Wunsch nahm es aus Kommentarbereich.

ich hier gelandet, weil ich mein Skript wollte ein Python-like Spleiß Argument akzeptieren und sie in eine Liste von ganzen Zahlen zu machen, ich habe es mit einer Funktion, die, wie es scheint, dass die OP Frage beantwortet:

# 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)

Ausgabe:

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

Hier ist eine andere Methode (nur eine Konsolidierung der anderen hier geschrieben):

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)

Beispiele für den Gebrauch:

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]

Der Einzeiler von Ignacio Vazquez-Abrams ist kurz, aber kaum lesbar und verarbeitet eine einzelne Zahl inkonsistent mit slice. Dieser versucht, es in einer sauberen Art und Weise zu analysieren.

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

Basierend auf @pprzemak entwarf die folgende Funktion für aufwendige Analyse:

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)

Wie wäre dies (für einfache, nicht leere Scheibe Intervalle):

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

Ein Stück Objekt in der Regel die Index-Notation erstellt wird, diese Schreibweise verwendet slice () intern, wie auf der slice () Dokumentation . Was Sie tun möchten, ist:

your_string[start:end]

das Python-Tutorial :

  

Strings können indexiert werden (indiziert);   wie in C, das erste Zeichen eines   String hat Index (Index) 0. Es   Art ist keine separate Zeichen; ein   Charakter ist einfach eine Reihe von Größe   einer. Wie in Icon kann Substrings sein   mit der Scheibe Schreibweise angegeben: Zwei   Indizes durch einen Doppelpunkt getrennt.

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

Slice-Indizes haben nützliche Standardwerte; ein   ersten Index Standardwert auf Null weggelassen,   eine zweite Index weggelassen Standardeinstellung   die Größe der Zeichenfolge geschnitten wird.

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

Meine Lösung numpy Stil erweiterte Indizierung von String zu analysieren: mein Kern . Obwohl dies eine alte Post, es ist die einzige, die ich zu diesem Thema finden können. Hoffe, es hilft.

Nach dem Vorschlag, füge ich den Code hier, die ein wenig lang sein könnten ... Der Code Nutzung ist (unter der Annahme, a ist ein Array-ähnliches Objekt): a[parse_slice('1')] gibt a[1]; a[parse_slice('2:,-1')] gibt 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top