2009-04-03 9 views
4

In einer Pylons Webapp muss ich eine Zeichenfolge wie "< 3, 45, 46, 48-51, 77" nehmen und eine Liste von Ints (die eigentlich IDs von Objekten sind) erstellen Suche auf.Interpretieren von Zahlenbereichen in Python

Irgendwelche Vorschläge zu Möglichkeiten, dies zu tun? Ich bin neu bei Python und habe da draußen nichts gefunden, was bei solchen Dingen hilft.

Die Liste wäre: [1, 2, 3, 45, 46, 48, 49, 50, 51, 77]

Antwort

12

Verwenden parseIntSet von here

I wie auch die pyparsing Implementierung in der Kommentare am Ende.

Das parseIntSet wurde hier geändert, um "< 3" -Einträge zu behandeln und die ungültigen Strings nur auszuspucken, wenn es welche gibt.

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

Und hier ist die Ausgabe von dem Probelauf:

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

Hat nicht die "<3" -Funktion, aber das könnte hinzugefügt werden (da es wirklich nur "1-3" oder "0-3" ist). +1. – paxdiablo

+0

Ich habe die Funktion "<3" zum Basisliniencode hinzugefügt. – paxdiablo

+0

warum importieren sys und os, wenn sie nie benutzt werden? – vartec

0

Zuerst müssen Sie herausfinden, was Syntax Art Sie akzeptieren. Sie Strom haben drei in Ihrem Beispiel:

  1. Einzelnummer: 45, 46

  2. Weniger als Betreiber

  3. Dash Bereich: 48-51

Danach, Es ist nur eine Frage der Aufteilung der Zeichenfolge in Tokens und Überprüfung des Formats des Tokens.

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

Geben Sie eine Liste mit einer arithmetischen Folge von Ganzzahlen zurück. Bereich (i, j) gibt zurück [i, i + 1, i + 2, ..., j-1]; start (!) ist standardmäßig 0. Wenn step angegeben wird, wird das Inkrement (oder Dekrement) angegeben. Zum Beispiel gibt Bereich (4) [0, 1, 2, 3] zurück. Der Endpunkt ist weggelassen! Dies sind genau die gültigen Indizes für eine Liste von 4 Elementen.

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

Ich kann mir vorstellen, dass Sie Ihre Liste iterieren und den Bereich entsprechend aufrufen können.

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

spalten dann die Zeichenfolge auf Komma, und für jedes Bit, analysieren es genug, um herauszufinden, was zu nennen funktionieren, catenating die zurückgegebenen Listen.

Alles mehr und ich hätte es für Sie geschrieben.

1
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 
0

Ich musste in letzter Zeit auch etwas ähnliches für eine App tun.

Wenn Sie keine konkreten Zahlen benötigen, sondern nur einen Weg, um zu sehen, ob eine bestimmte Zahl im Bereich liegt, können Sie sie in einem Python-Ausdruck analysieren, den Sie in ein Lambda einlesen können. Zum Beispiel <3, 5-10, 12 könnte func=(lambda x:x<3 or (5 <= x <= 10) or x==12)) sein.Dann kannst du einfach den Lambda, func(11) anrufen, um zu sehen, ob 11 da drin ist.