Регулярное выражение, совпадающее со строкой, представляющей собой последовательность токенов, разделенных точкой с запятой. - PullRequest
3 голосов
/ 25 июня 2019

Я пытаюсь создать строку регулярного выражения Python для проверки значений столбца, которые представляют собой разделенные запятыми последовательности уникальных трехбуквенных кодов из списка трехбуквенных (прописных) буквенно-цифровых кодов, например.список выглядит примерно так: ['XA1', 'CZZ', 'BT9', 'WFF',...].Таким образом, допустимые значения столбца могут быть XA1, XA1;CZZ или XA1;BT9;WFF; и т. Д. Код не может встречаться в последовательности более одного раза.

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

Если codes является списком кодов, тогда строка соответствия регулярному выражению, которую я построил из этого, равна

match_str = '?'.join(['({};){}'.format(code, '?' if codes[-1] == code else '') for code in codes])

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

'(XA1;)?(CZZ;)?(BT9;)?(WFF;)?'

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

re.match(match_str, 'XA1;')
re.match(match_str, 'XA1;WFF')
re.match(match_str, 'XA1;')

и т. Д.

In [124]: re.match(match_str, 'anystring')                                                                                        
Out[124]: <_sre.SRE_Match object; span=(0, 0), match=''>

In [125]: re.match(match_str, '')                                                                                                 
Out[125]: <_sre.SRE_Match object; span=(0, 0), match=''>

In [126]: re.match(match_str, 'XA1;something')                                                                                    
Out[126]: <_sre.SRE_Match object; span=(0, 4), match='XA1;'>

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

if re.match(match_str, val):
     # do something
else:
     # do something else

Ответы [ 2 ]

1 голос
/ 25 июня 2019

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

Используйте «обычный» Python:

codes = ['XA1', 'CZZ', 'BT9', 'WFF']
strs = ['XA1', 'XA1;CZZ', 'XA1;BT9;WFF;', 'XA1;XA1;', 'XA1;something']
for s in strs:
    chunks = s.strip(';').split(';')
    if set(chunks).issubset(codes) and len(chunks) == len(set(chunks)):
        print("{}: Valid!".format(s))
    else:
        print("{}: Invalid!".format(s))

См. Демо Python онлайн .

ПРИМЕЧАНИЯ :

  • chunks = s.strip(';').split(';') - удаляет начальное / конечное значение ; и разбивает строку на ;
  • if set(chunks).issubset(codes) and len(chunks) == len(set(chunks)): - проверяет, являются ли все полученные нами куски подмножеством codes, и удостоверяется, что каждый элемент внутри chunks уникален.

Решение Regex - НЕ ИСПОЛЬЗУЙТЕ В ПРОИЗВОДСТВЕ!

import re
codes = ['XA1', 'CZZ', 'BT9', 'WFF']
block = "(?:{})".format("|".join(codes))
rex =  re.compile( r"^(?!.*\b(\w+)\b.*\b\1\b){0}(?:;{0})*;?$".format(block) )
print(rex)

strs = ['XA1', 'XA1;CZZ', 'XA1;BT9;WFF;', 'XA1;XA1;', 'XA1;something']
for s in strs:
    if rex.match(s):
        print("{}: Valid!".format(s))
    else:
        print("{}: Invalid!".format(s))

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

0 голосов
/ 26 июня 2019

Это общее нерегулярное решение проблемы проверки, является ли строка ; -разделенной последовательностью уникальных / неповторяющихся кодов / токенов (из фиксированного набора таких токенов). Токены в строке могут быть в любом порядке, но допускается только одно вхождение любого токена, и строка может заканчиваться или не заканчиваться ;. Каждый токен в строке также не должен быть окружен пробелами.

Пример: пусть набор токенов будет набором или подмножеством двухбуквенных кодов стран, таких как {'AR', 'CA', 'GB', 'HK', 'IN', 'US'}. Тогда «действительными» строками в контексте этой проблемы могут быть такие, как AR;CA, HK;US;CA;GB;, US, HK;, а недопустимыми строками могут быть такие, как AR;CA, AR;something;HK;, something;AR;GB;US и т. д.

def is_valid_token_sequence(s, tokens, sep=';'):
    s_tokens = [t for t in s.split(sep) if t]
    token_cntr = collections.Counter(s_tokens).values()
    return not (
        any(t not in tokens for t in s_tokens) or
        any(v > 1 for v in token_cntr)
    )

>>> is_valid_token_sequence('AR;CA', codes)                                                                                                                                                                                        
>>> True

>>> is_valid_token_sequence('HK;US;CA;GB;', codes)                                                                                                                                                                                 
>>> True

>>> is_valid_token_sequence('IN', codes)                                                                                                                                                                                           
>>> True

>>> is_valid_token_sequence('HK;', codes)                                                                                                                                                                                          
>>> True

>>> is_valid_token_sequence(' AR;CA', codes)                                                                                                                                                                                       
>>> False

>>> is_valid_token_sequence('1234;AR;X1;IN;CA', codes)                                                                                                                                                                              
>>> False

>>> is_valid_token_sequence('X1;AR;GB;US', codes)                                                                                                                                                                           
>>> False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...