Pregunta

En una aplicación web Pilones, necesito tomar una cadena como "<3, 45, 46, 48-51, 77" y crear una lista de enteros (que en realidad son los ID de objetos) para buscar en.

Cualquier sugerencia acerca de maneras de hacer esto? Soy nuevo en Python, y no he encontrado nada por ahí que ayuda con este tipo de cosas.

La lista sería: [1, 2, 3, 45, 46, 48, 49, 50, 51, 77]

¿Fue útil?

Solución

El uso de parseIntSet rel="noreferrer">

También me gusta la aplicación pyparsing en los comentarios al final.

El parseIntSet ha sido modificado para manejar "<3" entradas de tipo y sólo para escupir las cadenas no válidas si los hay.

#! /usr/local/bin/python
import sys
import os

# return a set of selected values when a string in the form:
# 1-4,6
# would return:
# 1,2,3,4,6
# as expected...

def parseIntSet(nputstr=""):
    selection = set()
    invalid = set()
    # tokens are comma seperated values
    tokens = [x.strip() for x in nputstr.split(',')]
    for i in tokens:
        if len(i) > 0:
            if i[:1] == "<":
                i = "1-%s"%(i[1:])
        try:
            # typically tokens are plain old integers
            selection.add(int(i))
        except:
            # if not, then it might be a range
            try:
                token = [int(k.strip()) for k in i.split('-')]
                if len(token) > 1:
                    token.sort()
                    # we have items seperated by a dash
                    # try to build a valid range
                    first = token[0]
                    last = token[len(token)-1]
                    for x in range(first, last+1):
                        selection.add(x)
            except:
                # not an int and not a range...
                invalid.add(i)
    # Report invalid tokens before returning valid selection
    if len(invalid) > 0:
        print "Invalid set: " + str(invalid)
    return selection
# end parseIntSet

print 'Generate a list of selected items!'
nputstr = raw_input('Enter a list of items: ')

selection = parseIntSet(nputstr)
print 'Your selection is: '
print str(selection)

Y aquí está la salida de la ejecución de ejemplo:

$ python qq.py
Generate a list of selected items!
Enter a list of items: <3, 45, 46, 48-51, 77
Your selection is:
set([1, 2, 3, 45, 46, 77, 48, 49, 50, 51])

Otros consejos

He creado una versión de la solución de @ VarTec que siento es más fácil de leer:

def _parse_range(numbers: str):
    for x in numbers.split(','):
        x = x.strip()
        if x.isdigit():
            yield int(x)
        elif x[0] == '<':
            yield from range(0, int(x[1:]))
        elif '-' in x:
            xr = x.split('-')
            yield from range(int(xr[0].strip()), int(xr[1].strip())+1)
        else:
            raise ValueError(f"Unknown range specified: {x}")

En el proceso, la función se convirtió en un generador:)

rng = "<3, 45, 46, 48-51, 77"
ids = []
for x in map(str.strip,rng.split(',')):
    if x.isdigit():
        ids.append(int(x))
        continue
    if x[0] == '<':
        ids.extend(range(1,int(x[1:])+1))
        continue
    if '-' in x:
        xr = map(str.strip,x.split('-'))
        ids.extend(range(int(xr[0]),int(xr[1])+1))
        continue
    else:
        raise Exception, 'unknown range type: "%s"'%x

En primer lugar, usted tiene que averiguar qué tipo de sintaxis que aceptará. Usted actual tiene tres en el ejemplo:

  1. número individual: 45, 46

  2. Menos de operador

  3. Dash que van: 48-51

Después de eso, es sólo una cuestión de dividir la cadena en tokens, y comprobar el formato de la ficha.

>>> print range.__doc__
range([start,] stop[, step]) -> list of integers

Devuelve una lista que contiene una progresión aritmética de números enteros. rango (i, j) regresa [i, i + 1, i + 2, ..., j-1]; iniciar (!) por defecto es 0. Cuando se da paso, se especifica el incremento (o decremento). Por ejemplo, el rango (4) devuelve [0, 1, 2, 3]. se omite el punto final! Estos son exactamente los índices válidos para una lista de los 4 elementos.

>>> range(33,44)
[33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]
>>> range(1,3)
[1, 2]

Me imagino que podría repetir su lista, y la llamada están comprendidas adecuadamente.

>>> def lessThan(n) :
...  return range(n+1)
...
>>> lessThan(4)
[0, 1, 2, 3, 4]
>>> def toFrom(n,m):
...  return range(n,m)
...
>>> toFrom(33,44)
[33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]

A continuación, dividir la cadena de comas, y para cada bit, analizarlo suficiente para averiguar qué función a llamar, catenating las listas devueltas.

Nada más y me lo he escrito para ti.

También tenía que hacer algo similar para una aplicación últimamente.

Si usted no necesita números concretos, pero sólo una manera de ver si un número dado es en el rango, es posible considerar el análisis a una expresión de Python se puede eval en una lambda. Por ejemplo <3, 5-10, 12 podría func=(lambda x:x<3 or (5 <= x <= 10) or x==12)). A continuación, sólo puede llamar a la lambda, func(11) 11 para ver si pertenece en ese país.

scroll top