Python中如何使用字符串创建切片对象。

12

我想从一个字符串创建切片对象;目前唯一的方法似乎是通过冗长和繁琐的eval语句。

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

提前谢谢。

编辑: 如果原问题没有表述清楚,在这种情况下输入是“:-1”。重点是解析字符串。Ignacio Vazquez-Abrams的回答至少解决了问题(并且似乎也适用于反向索引),但我认为我的解决方案仍然更清晰,尽管不太概念上干净(如果Python改变切片语法,它也将正确工作)。


你能否更清楚地说明你想要的行为是什么? - Andrew Jaffe
为什么要创建独立的切片对象?切片是一流的语法结构,如果不知道为什么要这样做,这个问题就很奇怪。 - S.Lott
Jaffe:问题已更新。 Lott:我正在进行一些语言处理工作,希望也能使用Python切片。实际对象非常有用:它具有indices(len)函数,可以在给定数组长度的情况下提供(开始,停止,增量)。 - gatoatigrado
@gatoatigrado:是的,Slice()对象很有用。内置的slice函数有什么问题吗?问题在于它无法正确解析源表示形式吗? - S.Lott
也许我很蠢,但我仍然不明白你想要什么! - Andrew Jaffe
1
内置的切片函数需要三个参数 - 开始、停止和步长。我想解析一个字符串,例如 "0:1" --> slice(0, 1, None); ":-1" --> slice(None, -1, None), "3::2" --> slice(3, None, 2)。 - gatoatigrado
11个回答

-1

我解析numpy风格高级索引字符串的解决方案:我的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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接