Как составить регулярное выражение с плавающей точкой и ограничением?

Как составить регулярное выражение, которое пропускает число с плавающей точкой от -29999984 до 29999983?

у меня уже есть регулярное выражение, которое пропускает число с плавающей точкой:

[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)

осталось лишь наложить на него ограничения

Я бы хотел видеть такое регулярное выражение, в которое я мог подставить любое минимальное число и любое максимальное


Ответы (3 шт):

Автор решения: mazik7512

Регулярные выражения воспринимают данные как строки, а не как числа, следовательно выполнять логические операции над данными они не могут. Вашу задачу правильнее и легче будет сделать с помощью if-else.

С использованием регулярных выражений такое решение сделать либо не получиться вовсе, либо оно будет очень громоздким.

Здесь есть пример ограничения от 1 до 16, но как там правильно указано данное решение не является масштабируемым.

→ Ссылка
Автор решения: Stanislav Volodarskiy

Баловство это всё. Вот пример регулярного выражения для неотрицательных вещественных чисел с фиксированной запятой в диапазоне [0, 29999983]:

import re


def expr():
    return '|'.join(f'(^{s}$)' for s in (
        '[0-9]{1,7}(\.[0-9]*)?'         , #             s < 10000000
        '1[0-9]{7}(\.[0-9]*)?'          , # 10000000 <= s < 20000000
        '2[0-8][0-9]{6}(\.[0-9]*)?'     , # 20000000 <= s < 29000000
        '29[0-8][0-9]{5}(\.[0-9]*)?'    , # 29000000 <= s < 29900000
        '299[0-8][0-9]{4}(\.[0-9]*)?'   , # 29900000 <= s < 29990000
        '2999[0-8][0-9]{3}(\.[0-9]*)?'  , # 29990000 <= s < 29999000
        '29999[0-8][0-9]{2}(\.[0-9]*)?' , # 29999000 <= s < 29999900
        '299999[0-7][0-9](\.[0-9]*)?'   , # 29999900 <= s < 29999980
        '2999998[0-2](\.[0-9]*)?'       , # 29999980 <= s < 29999983
        '29999983(\.[0]*)?'             , # 29999983 == s
    ))


def less(s):
    return re.search(expr(), s) is not None


def test(s):
    print(less(s), repr(s))
    assert less(s) == (float(s) <= 29999983)

    
print(expr())
test('0')
test('1')
test('1.0001')
test('9999999')
test('9999999.33')
test('19999999')
test('19999999.33')
test('28999999')
test('28999999.33')
test('29899999')
test('29899999.33')
test('29989999')
test('29989999.33')
test('29998999')
test('29998999.33')
test('29999899')
test('29999899.33')
test('29999979')
test('29999979.33')
test('29999982')
test('29999982.33')
test('29999983')
test('29999983.00')
test('29999983.01')
test('29999984')
test('29999984.01')
test('29999990')
test('29999990.01')
test('30000000')
test('30000000.01')
test('99999999')
test('999999999')

Регулярка разбитая по строкам для удобства:

(^[0-9]{1,7}(\.[0-9]*)?$)|
(^1[0-9]{7}(\.[0-9]*)?$)|
(^2[0-8][0-9]{6}(\.[0-9]*)?$)|
(^29[0-8][0-9]{5}(\.[0-9]*)?$)|
(^299[0-8][0-9]{4}(\.[0-9]*)?$)|
(^2999[0-8][0-9]{3}(\.[0-9]*)?$)|
(^29999[0-8][0-9]{2}(\.[0-9]*)?$)|
(^299999[0-7][0-9](\.[0-9]*)?$)|
(^2999998[0-2](\.[0-9]*)?$)|
(^29999983(\.[0]*)?$)

Регулярка:

(^[0-9]{1,7}(\.[0-9]*)?$)|(^1[0-9]{7}(\.[0-9]*)?$)|(^2[0-8][0-9]{6}(\.[0-9]*)?$)|(^29[0-8][0-9]{5}(\.[0-9]*)?$)|(^299[0-8][0-9]{4}(\.[0-9]*)?$)|(^2999[0-8][0-9]{3}(\.[0-9]*)?$)|(^29999[0-8][0-9]{2}(\.[0-9]*)?$)|(^299999[0-7][0-9](\.[0-9]*)?$)|(^2999998[0-2](\.[0-9]*)?$)|(^29999983(\.[0]*)?$)

Отрицательный диапазон строится по аналогии. Нетрудно написать автоматический генератор.

→ Ссылка
Автор решения: MIkhail

Stanislav Volodarskiy Дал правильное решение.

только чтобы учесть весь диапазон, нужно расширить это

def expr():
    return '|'.join(f'(^{s}$)' for s in (
        '[0-9]{1,7}(\.[0-9]*)?'         , #             s < 10000000
        '1[0-9]{7}(\.[0-9]*)?'          , # 10000000 <= s < 20000000
        '2[0-8][0-9]{6}(\.[0-9]*)?'     , # 20000000 <= s < 29000000
        '29[0-8][0-9]{5}(\.[0-9]*)?'    , # 29000000 <= s < 29900000
        '299[0-8][0-9]{4}(\.[0-9]*)?'   , # 29900000 <= s < 29990000
        '2999[0-8][0-9]{3}(\.[0-9]*)?'  , # 29990000 <= s < 29999000
        '29999[0-8][0-9]{2}(\.[0-9]*)?' , # 29999000 <= s < 29999900
        '299999[0-7][0-9](\.[0-9]*)?'   , # 29999900 <= s < 29999980
        '2999998[0-2](\.[0-9]*)?'       , # 29999980 <= s < 29999983
        '29999983(\.[0]*)?'             , # 29999983 == s
    ))

на это:

def expr():
    return '|'.join(f'(^{s}$)' for s in (
        '-[0-9]{1,7}(\.[0-9]*)?' 
        '-1[0-9]{7}(\.[0-9]*)?',
        '-2[0-8][0-9]{6}(\.[0-9]*)?',
        '-29[0-8][0-9]{5}(\.[0-9]*)?',
        '-299[0-8][0-9]{4}(\.[0-9]*)?',
        '-2999[0-8][0-9]{3}(\.[0-9]*)?',
        '-29999[0-8][0-9]{2}(\.[0-9]*)?',
        '-299999[0-7][0-9](\.[0-9]*)?',
        '-2999998[0-3](\.[0-9]*)?',
        '-29999984(\.[0]*)?',
        '[0-9]{1,7}(\.[0-9]*)?'         , #             s < 10000000
        '1[0-9]{7}(\.[0-9]*)?'          , # 10000000 <= s < 20000000
        '2[0-8][0-9]{6}(\.[0-9]*)?'     , # 20000000 <= s < 29000000
        '29[0-8][0-9]{5}(\.[0-9]*)?'    , # 29000000 <= s < 29900000
        '299[0-8][0-9]{4}(\.[0-9]*)?'   , # 29900000 <= s < 29990000
        '2999[0-8][0-9]{3}(\.[0-9]*)?'  , # 29990000 <= s < 29999000
        '29999[0-8][0-9]{2}(\.[0-9]*)?' , # 29999000 <= s < 29999900
        '299999[0-7][0-9](\.[0-9]*)?'   , # 29999900 <= s < 29999980
        '2999998[0-2](\.[0-9]*)?'       , # 29999980 <= s < 29999983
        '29999983(\.[0]*)?'             , # 29999983 == s
    ))

и конечное регулярное выражение будет следующим:

(^-1[0-9]{7}(\.[0-9]*)?$)|(^-2[0-8][0-9]{6}(\.[0-9]*)?$)|(^-29[0-8][0-9]{5}(\.[0-9]*)?$)|(^-299[0-8][0-9]{4}(\.[0-9]*)?$)|(^-2999[0-8][0-9]{3}(\.[0-9]*)?$)|(^-29999[0-8][0-9]{2}(\.[0-9]*)?$)|(^-299999[0-7][0-9](\.[0-9]*)?$)|(^-2999998[0-3](\.[0-9]*)?$)|(^-29999984(\.[0]*)?$)|(^[0-9]{1,7}(\.[0-9]*)?$)|(^1[0-9]{7}(\.[0-9]*)?$)|(^2[0-8][0-9]{6}(\.[0-9]*)?$)|(^29[0-8][0-9]{5}(\.[0-9]*)?$)|(^299[0-8][0-9]{4}(\.[0-9]*)?$)|(^2999[0-8][0-9]{3}(\.[0-9]*)?$)|(^29999[0-8][0-9]{2}(\.[0-9]*)?$)|(^299999[0-7][0-9](\.[0-9]*)?$)|(^2999998[0-2](\.[0-9]*)?$)|(^29999983(\.[0]*)?$)

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

def expr():
    return '|'.join(f'(^{s}$)' for s in (
        '[+-]?[0-9]{1,7}(\.[0-9]*)?|\.[0-9]+',
        '[+-]?1[0-9]{7}(\.[0-9]*)?',
        '[+-]?2[0-8][0-9]{6}(\.[0-9]*)?',
        '[+-]?29[0-8][0-9]{5}(\.[0-9]*)?',
        '[+-]?299[0-8][0-9]{4}(\.[0-9]*)?',
        '[+-]?2999[0-8][0-9]{3}(\.[0-9]*)?',
        '[+-]?29999[0-8][0-9]{2}(\.[0-9]*)?',
        '[+-]?299999[0-7][0-9](\.[0-9]*)?',
        '\-2999998[0-3](\.[0-9]*)?',
        '[+]?2999998[0-2](\.[0-9]*)?',
        '\-29999984(\.[0]*)?',
        '29999983(\.[0]*)?',
    ))

и конечное регулярное выражение будет следующим:

(^[+-]?[0-9]{1,7}(\.[0-9]*)?|\.[0-9]+$)|(^[+-]?1[0-9]{7}(\.[0-9]*)?$)|(^[+-]?2[0-8][0-9]{6}(\.[0-9]*)?$)|(^[+-]?29[0-8][0-9]{5}(\.[0-9]*)?$)|(^[+-]?299[0-8][0-9]{4}(\.[0-9]*)?$)|(^[+-]?2999[0-8][0-9]{3}(\.[0-9]*)?$)|(^[+-]?29999[0-8][0-9]{2}(\.[0-9]*)?$)|(^[+-]?299999[0-7][0-9](\.[0-9]*)?$)|(^\-2999998[0-3](\.[0-9]*)?$)|(^[+]?2999998[0-2](\.[0-9]*)?$)|(^\-29999984(\.[0]*)?$)|(^29999983(\.[0]*)?$)
→ Ссылка