Creating slice notation from string
Paul McGuire
ptmcg at austin.rr.com
Thu Sep 3 00:46:25 EDT 2009
On Sep 2, 4:55 pm, bvdp <b... at mellowood.ca> wrote:
> I'm trying to NOT create a parser to do this .... and I'm sure that
> it's easy if I could only see the light!
>
Well, this is a nice puzzler, better than a sudoku. Maybe a quick
parser with pyparsing will give you some guidance on how to do this
without a parser library:
from pyparsing import *
# relevant punctuation, suppress after parsing
LBR,RBR,COLON = map(Suppress,"[]:")
# expression to parse numerics and convert to int's
integer = Regex("-?\d+").setParseAction(lambda t: int(t[0]))
# first try, almost good enough, but wrongly parses "[2]" -> [2::]
sliceExpr = ( LBR + Optional(integer,default=None) +
Optional(COLON + Optional(integer,default=None),
default=None) +
Optional(COLON + Optional(integer,default=None),
default=None) +
RBR )
# better, this version special-cases "[n]" -> [n:n+1]
# otherwise, just create slice from parsed int's
singleInteger = integer + ~FollowedBy(COLON)
singleInteger.setParseAction(lambda t : [t[0],t[0]+1])
sliceExpr = ( LBR +
(singleInteger |
Optional(integer,default=None) +
Optional(COLON + Optional(integer,default=None),
default=None) +
Optional(COLON + Optional(integer,default=None),
default=None)
) +
RBR )
# attach parse action to convert parsed int's to a slice
sliceExpr.setParseAction(lambda t: slice(*(t.asList())))
tests = """\
[2]
[2:3]
[2:]
[2::2]
[-1:-1:-1]
[:-1]
[::-1]
[:]""".splitlines()
testlist = range(10)
for t in tests:
parsedSlice = sliceExpr.parseString(t)[0]
print t, parsedSlice, testlist[parsedSlice]
Prints:
[2] slice(2, 3, None) [2]
[2:3] slice(2, 3, None) [2]
[2:] slice(2, None, None) [2, 3, 4, 5, 6, 7, 8, 9]
[2::2] slice(2, None, 2) [2, 4, 6, 8]
[-1:-1:-1] slice(-1, -1, -1) []
[:-1] slice(None, -1, None) [0, 1, 2, 3, 4, 5, 6, 7, 8]
[::-1] slice(None, None, -1) [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
[:] slice(None, None, None) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Yes, it is necessary to handle the special case of a "slice" that is
really just a single index. If your list of parsed integers has only
a single value n, then the slice constructor creates a slice
(None,n,None). What you really want, if you want everything to create
a slice, is to get slice(n,n+1,None). That is what the singleInteger
special case does in the pyparsing parser.
-- Paul
More information about the Python-list
mailing list