Интерпретация числовых диапазонов в Python - PullRequest
4 голосов
/ 03 апреля 2009

В веб-приложении Pylons мне нужно взять строку типа «<3, 45, 46, 48-51, 77» и создать список целых чисел (которые фактически являются идентификаторами объектов) для поиска. </p>

Есть предложения о том, как это сделать? Я новичок в Python, и я не нашел ничего такого, что могло бы помочь с такими вещами.

Список будет: [1, 2, 3, 45, 46, 48, 49, 50, 51, 77]

Ответы [ 5 ]

12 голосов
/ 03 апреля 2009

Используйте parseIntSet от здесь

Мне также нравится реализация pyparsing в комментариях в конце.

ParseIntSet был изменен здесь для обработки записей типа «<3» и для того, чтобы выдавать недопустимые строки, только если они есть. </p>

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

А вот результат выполнения примера:

$ 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])
1 голос
/ 03 апреля 2009
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 голосов
/ 03 апреля 2009

В последнее время мне тоже приходилось делать что-то похожее для приложения.

Если вам нужны не конкретные числа, а просто способ узнать, находится ли данное число в диапазоне, вы можете рассмотреть его разбор в выражение Python, которое вы можете преобразовать в лямбду. Например, <3, 5-10, 12 может быть func=(lambda x:x<3 or (5 <= x <= 10) or x==12)). Тогда вы можете просто позвонить в лямбду, func(11), чтобы узнать, принадлежит ли там 11.

0 голосов
/ 03 апреля 2009
>>> print range.__doc__
range([start,] stop[, step]) -> list of integers

Возвращает список, содержащий арифметическую последовательность целых чисел. range (i, j) возвращает [i, i + 1, i + 2, ..., j-1]; начало (!) по умолчанию равно 0. Когда задан шаг, он определяет приращение (или уменьшение). Например, range (4) возвращает [0, 1, 2, 3]. Конечная точка опущена! Это в точности действительные индексы для списка из 4 элементов.

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

Полагаю, вы могли бы повторить свой список и соответствующим образом указать диапазон вызовов.

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

Затем разбейте строку на запятые и для каждого бита проанализируйте его достаточно, чтобы выяснить, какую функцию вызывать, объединяя возвращаемые списки.

Что-нибудь еще, и я бы написал это для вас.

0 голосов
/ 03 апреля 2009

Во-первых, вам нужно выяснить, какой синтаксис вы принимаете. У вас сейчас три в вашем примере:

  1. Одно число: 45, 46

  2. Меньше, чем оператор

  3. Тире: 48-51

После этого нужно просто разбить строку на токены и проверить формат токена.

...