Domanda

In una webapp Piloni, ho bisogno di prendere una stringa come "<3, 45, 46, 48-51, 77" e creare un elenco di numeri interi (che in realtà sono gli ID degli oggetti) per cercare.

Tutti i suggerimenti su modi per fare questo? Sono nuovo di Python, e non ho trovato nulla là fuori che aiuta con questo genere di cose.

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

È stato utile?

Soluzione

Usa parseIntSet da href="http://thoughtsbyclayg.blogspot.com/2008/10/parsing-list-of-numbers-in-python.html" qui

Mi piace anche l'attuazione pyparsing nei commenti alla fine.

Il parseIntSet è stato modificato qui per gestire "<3" voci -tipo e di sputare solo le stringhe non valide se ce ne sono.

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

Ed ecco l'output del esempio di esecuzione:

$ 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])

Altri suggerimenti

Ho creato una versione della soluzione @ di Vartec che mi sembra più leggibile:

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}")

Nel processo, la funzione è diventato un generatore:)

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

In primo luogo, è necessario capire che tipo di sintassi che accetterai. È corrente hanno tre nel tuo esempio:

  1. Numero singolo: 45, 46

  2. A meno di operatore

  3. Dash che vanno: 48-51

Dopo di che, è solo una questione di suddividere la stringa in token, e verificare il formato del token.

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

Restituisce una lista contenente una progressione aritmetica di numeri interi. Campo (i, j) restituisce [i, i + 1, i + 2, ..., j-1]; iniziare (!) il valore predefinito è 0. Quando viene dato passo, specifica l'incremento (o decremento). Ad esempio, gamma (4) restituisce [0, 1, 2, 3]. Il punto finale viene omesso! Questi sono esattamente gli indici validi per un elenco di 4 elementi.

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

Immagino che si potrebbe iterare la vostra lista, e chiamate va in modo appropriato.

>>> 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]

Poi dividere la stringa su virgole, e per ogni bit, analizzarlo abbastanza per capire che cosa funziona per chiamare, catenating le liste restituite.

Qualche cosa di più e avrei scritto per voi.

Ho anche dovuto fare qualcosa di simile per un app ultimamente.

Se non avete bisogno di numeri concreti, ma solo un modo per vedere se un dato numero è nella gamma, si potrebbe considerare l'analisi ad un'espressione Python si può eval in un lambda. Per esempio potrebbe essere <3, 5-10, 12 func=(lambda x:x<3 or (5 <= x <= 10) or x==12)). Poi si può chiamare il lambda, func(11) per vedere se 11 appartiene in là.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top