Numero Interpretazione Ranges in Python
-
23-08-2019 - |
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]
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:
-
Numero singolo: 45, 46
-
A meno di operatore
-
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à.