Регулярное выражение, чтобы соответствовать только уникальное имя, разделенное запятой - PullRequest
0 голосов
/ 11 января 2019

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

Длина каждого имени должна быть между 3 и 20 .

Допустимые строки:

JOHN, MARK, EDDIE

JOHN

НЕ Принимаются строки:

JOHN

ДЖОН МАРК

JOHN , MARK, EDDIE JOHN

Я использую следующее регулярное выражение, которое гарантирует, что имена должны быть разделены запятой (если их больше одного), но как я могу сказать, что имена должны быть уникальными?

^([A-Z]{3,20})(,[A-Z]{3,20})*$

Ответы [ 2 ]

0 голосов
/ 12 января 2019

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

^[A-Z]{3,20}(?:,[A-Z]{3,20})*$

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

Например

import re
strings = ["JOHN,MARK,EDDIE", "JOHN", "JOHN,", "JOHN MARK", "JOHN,MARK,EDDIE,JOHN"]

for s in strings:
    m = re.match("^[A-Z]{3,20}(?:,[A-Z]{3,20})*$", s)

    if m:
        parts = s.split(',')
        res = len(parts) == len(set(parts))
        print("{}:{}".format(s, res))

Результат

JOHN,MARK,EDDIE:True
JOHN:True
JOHN,MARK,EDDIE,JOHN:False

См. Демоверсию regex | Python demo

0 голосов
/ 11 января 2019

Вы можете использовать отрицательный прогноз , который цитирует a подходящее имя :

r'(([a-z]+),?(?!.*\2))+'

Часть (?!.*\2) гарантирует, что совпадающее имя не появится позже. Это служит примером того, как использовать негативную перспективу. Полное регулярное выражение в соответствии с требованиями OP:

re.match(r'^(([A-Z]{3,20})(?![A-Z,]*,\2,),)+$', string + ',')

Обратите внимание, что это проверяет string + ',', то есть искусственную запятую, чтобы избежать путаницы с двумя разными группами для первой и последующих частей.

Я полагаю, что негативное предвидение является коротким замыканием в том смысле, что оно терпит неудачу, как только встречает совпадение. Это означает, что производительность в худшем случае должна быть O (N ^ 2). Мы можем проверить это, сгенерировав строки, которые содержат только уникальные имена, и измерить производительность регулярных выражений. Квадратичная подгонка дает t = a*N**2 + c и a = 0.06 us, c = 3 us.

Timing plot

код

from random import choice, sample
from string import ascii_lowercase as lowercase
import re
import time

N = 500
data = [None] * N
for i in range(N):
    length = choice(range(3, 21))
    x = ''.join(sample(lowercase, length))
    while sample in data:
        length = choice(range(3, 21))
        x = ''.join(sample(lowercase, length))
    data[i] = x

pattern = re.compile(r'^(([a-z]+),?(?!.*\2))+$')
timings = []
for i in range(2, N+1):
    print('Begin iteration. ', end='', flush=True)
    string = ','.join(data[:i])
    print(f'Run for {i} unique names (lenght = {len(string)}) ... ', end='', flush=True)
    t1 = time.clock()
    m = re.match(pattern, string)
    t2 = time.clock()
    print('done.', end='', flush=True)
    assert m is not None
    timings.append(t2 - t1)
    print(' End iteration.', flush=True)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...