10

我想从一个字符串创建一个切片对象;现在唯一的方法似乎是通过一个繁琐的 hacky eval 语句

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

提前致谢。

编辑:对不起,如果原始提示不清楚,在这种情况下输入是“:-1”。关键是解析字符串。Ignacio Vazquez-Abrams 的回应至少解决了这个问题(并且似乎也适用于反向索引),但我认为我上面的解决方案如果在概念上不干净(如果 Python 改变切片语法将正常工作)。

4

11 回答 11

4

如果你想要一个切片对象,为什么不实例化一个呢?

s = slice(start, stop, step)

“从字符串创建它”是什么意思?

于 2009-03-25T09:46:12.147 回答
4

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

对于单个 arg 切片'-1'左右'1',当mystring.split(':')==1您调用时int(x)

根据要求,将其从评论部分中删除。

于 2018-06-29T16:27:48.757 回答
2
slice(*[{True: lambda n: None, False: int}[x == ''](x) for x in (mystring.split(':') + ['', '', ''])[:3]])
于 2009-03-25T14:51:40.167 回答
2

我最终来到这里是因为我希望我的脚本接受一个类似 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]
于 2014-05-27T17:18:06.707 回答
1

这是另一种方法(只是此处发布的其他方法的合并):

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]
于 2017-11-14T21:36:03.400 回答
1

来自 Ignacio Vazquez-Abrams 的单行代码很短但难以阅读,并且处理单个数字与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
于 2019-01-29T12:28:08.820 回答
0

基于@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)
于 2017-08-10T13:09:11.030 回答
0

这个怎么样(对于简单的非空切片间隔):

sliceStr = "3:8"
mySlice = slice( *map(int, sliceStr.split(':') ) )
于 2018-06-29T14:20:01.860 回答
0

12年后我只需要这样做,所以这是我使用正则表达式的答案:)

import re
def parse_slice(string: str) -> slice:
    """
    Parse a string representation of a slice and return a slice object
    """
    # Matches one required colon, one optional colon, and up to three
    # positive or negative numbers between them
    match = re.match(r"^(-?[\d]*):(-?[\d]*)[:]?(-?[\d]*)$", string)
    if match:
        args = tuple(map(lambda s: int(s) if s else None, match.group(1, 2, 3)))
        return slice(*args)
    raise ValueError("Could not parse slice")
于 2021-08-23T21:36:37.603 回答
-1

切片对象通常使用下标表示法创建,该表示法在内部使用 slice(),如slice() 文档中所述。你想做的是:

your_string[start:end]

python教程

字符串可以下标(索引);就像在 C 中一样,字符串的第一个字符的下标(索引)为 0。没有单独的字符类型;一个字符只是一个大小为 1 的字符串。就像在 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'
于 2009-03-25T14:42:28.753 回答
-1

我从字符串解析 numpy 样式高级索引的解决方案:my gist。虽然这是一篇旧文章,但它是我能找到的关于这个主题的唯一一篇。希望能帮助到你。

根据建议,我将代码粘贴在这里,可能有点长......代码用法是(假设a是一个类似数组的对象):给; 等等a[parse_slice('1')]a[1]a[parse_slice('2:,-1')]a[2:,-1]

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
于 2019-08-20T13:07:59.100 回答