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

Вот простое выражение, с которым я работаю:

"^[0-9]{13}$"

Это соответствует строке чисел длиной ровно 13 символов. Согласно документации Python, я могу установить такой диапазон, который будет соответствовать строке чисел длиной от 13 до 20 символов, например:

"^[0-9]{13,20}$"

Мой вопрос: как я могу исключить определенные «длины» из диапазона? Например:

"^[0-9]{13,20 EXCEPT for 15 or 17}$"

В этом примере я хочу включить любую длину от 13 до 20, ЗА ИСКЛЮЧЕНИЕМ 15 и 17.

Это возможно?

Я просмотрел документацию по регулярным выражениям Python 3 и лично не могу найти способ сделать это, но у меня еще нет опыта работы с этим, поэтому я мог что-то упустить.

1
csharp1321 30 Окт 2023 в 04:53
2
Нет, это невозможно. Просто просмотрите спички и отбросьте те, которые имеют неправильную длину. Регулярное выражение уже проделало тяжелую работу.
 – 
Tim Roberts
30 Окт 2023 в 04:54
1
^(?!.{15}$)(?!.{17}$)[0-9]{13,20}$ — два отрицательных просмотра отклоняют любую строку одной из запрещенных длин. Я не говорю, что это хороший способ реализовать ваше требование, просто это возможно.
 – 
jasonharper
30 Окт 2023 в 05:01
^[0-9]{13}([0-9]([0-9][0-9]([0-9][0-9]{1,3})?)?)?$, но регулярное выражение Джейсона более читабельно
 – 
rioV8
30 Окт 2023 в 05:10

2 ответа

Ну... да, можно, но для этого потребуется больше, чем один квантификатор.

С альтернативами:

^
(?:
  [0-9]{13,14}   # 13 or 14
|
  [0-9]{16}      # or 16
|
  [0-9]{18,20}   # or 18, 19, 20.
)
$

С просмотром:

^
(?!.{15}$)(?!.{17}$)    # Assure that the length is neither 15 nor 17,
[0-9]{13,20}            # and at the same time, 13 <= length <= 20.
$

С просмотром назад:

^
[0-9]{13,20}            # Basically the same pattern,
(?<!^.{15})(?<!^.{17})  # just inverted.
$

С обычным кодом Python:

# Note the lack of anchors and the use of .fullmatch()
# That method is used here since it is more readable,
# and it automatically adds anchors.

_13_to_20_digits = re.compile('[0-9]{13,20}')

if _13_to_20_digits.fullmatch(text) and len(text) not in (15, 17):
  frobnicate()

[нужна цитата]

0
InSync 30 Окт 2023 в 05:20

Во втором шаблоне вы можете заменить начало строки ^ на пользовательский/ограниченный ^(?!(.{15}|.{17})$) (который создается на основе исключаемой длины). Это обеспечит совпадение каждого начала строки, но только если ее длина не составляет 15 или 17 символов.

Use ^(?!(.{15}|.{17})$)[0-9]{13,20}$ instead of ^[0-9]{13,20}$

А вот общий код для обработки различных прерывистых диапазонов:

# feel free to adjust the values
(l, r), excep = [13, 20], [15, 17]

to_excl = "|".join(".{%s}" % n for n in excep)

pat = re.compile(r"^(?!(%s)$)[0-9]{%s,%s}$" % (to_excl, l, r))

Тест/выход:

for t in text:
    print(
        f"{t:<22}", f"{len(t):<4}",
        "match" if pat.match(t) else "no-match"
    )
    
01234                  5    no-match
012345678901234        15   no-match
0123456789012345       16   match
01234567890123456      17   no-match
012345678901234567     18   match
012345678901234567890  21   no-match

Используемый вход:

from string import digits
s = digits; lens = [5, 15, 16, 17, 18, 21]
text = [s * (l // 10) + s[:l % 10] for l in lens]
   
['01234',
 '012345678901234',
 '0123456789012345',
 '01234567890123456',
 '012345678901234567',
 '012345678901234567890']
0
Timeless 30 Окт 2023 в 06:25