Как проверить, что регулярное выражение полностью соответствует строке, т. Е. Строка не содержит лишних символов? - PullRequest
1 голос
/ 07 октября 2010

У меня два вопроса:

1) У меня есть регулярное выражение ([A-Z][a-z]{0,2})(\d*), и я использую Python re.finditer() для сопоставления с соответствующими строками. Моя проблема в том, что я хочу сопоставлять только строки, которые не содержат лишних символов, в противном случае я хочу вызвать исключение.

Я хочу поймать следующую схему: - заглавная буква, за которой следуют 0, 1 или 2 строчные буквы, за которыми следуют 0 или более цифр.

Шаблон представляет собой химическую формулу, то есть атом, за которым следует число его появлений. Я хочу поместить атом в словарь с его количеством вхождений, поэтому мне нужно разделить атомы (заглавная буква, затем 0, 1 или 2 строчные буквы) и цифры, но помните, что они принадлежат друг другу.

Пример:

C6H5Fe2I   # this string should be matched successfully. Result: C6 H5 Fe2 I
H2TeO4     # this string should be matched successfully Result: H2 Te O4
H3PoooO5   # exception should be raised
C2tH6      # exception should be raised

2) Второй вопрос: какой тип исключения я должен вызвать в случае, если введенная строка неверна.

Спасибо, Томас

Ответы [ 9 ]

4 голосов
/ 07 октября 2010

Вот несколько различных подходов, которые вы можете использовать:

Сравнить длины

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

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

Регулярное выражение для всей строки

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

^([A-Z][a-z]{0,2}\d*)*$

(Rubular)

Tokenize

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

[A-Z][^A-Z]*

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

3 голосов
/ 07 октября 2010

заглавная буква, за которой следуют 0, 1 или 2 маленькие буквы, за которыми следуют 0 или более число

Хорошо, тогда.

/^([A-Z][a-z]{0,2}\d*)+$/

Разница здесь заключается в дополнительной группировке (foo)+ внутри ^$, позволяющей вам захватить паттерн foo N раз.

Нет глобального флага? Думаю, вам придется снова разделить результат этого регулярного выражения на шаблоне.

2 голосов
/ 07 октября 2010
>>> import re
>>> reMatch = re.compile( '([A-Z][a-z]{0,2})(\d*)' )
>>> def matchText ( text ):
        matches, i = [], 0
        for m in reMatch.finditer( text ):
            if m.start() > i:
                break
            matches.append( m )
            i = m.end()
        else:
            if i == len( text ):
                return matches
        raise ValueError( 'invalid text' )

>>> matchText( 'C6H5Fe2I' )
[<_sre.SRE_Match object at 0x021E2800>, <_sre.SRE_Match object at 0x021E28D8>, <_sre.SRE_Match object at 0x021E2920>, <_sre.SRE_Match object at 0x021E2968>]
>>> matchText( 'H2TeO4' )
[<_sre.SRE_Match object at 0x021E2890>, <_sre.SRE_Match object at 0x021E29F8>, <_sre.SRE_Match object at 0x021E2A40>]
>>> matchText( 'H3PoooO5' )
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    matchText( 'H3PoooO5' )
  File "<pyshell#3>", line 11, in matchText
    raise ValueError( 'invalid text' )
ValueError: invalid text
>>> matchText( 'C2tH6' )
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    matchText( 'C2tH6' )
  File "<pyshell#3>", line 11, in matchText
    raise ValueError( 'invalid text' )
ValueError: invalid text

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

2 голосов
/ 07 октября 2010

Вам нужно извлечь каждую отдельную деталь для обработки или просто сопоставить для проверки ввода? Если вам просто нужно соответствовать для проверки, попробуйте ^([A-Z][a-z]{0,2}\d*)+$.

2 голосов
/ 07 октября 2010

Вам нужно немного другое регулярное выражение:

^([A-Z][a-z]{0,2})(\d*)$

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

Просто для проверки соответствия всей строки:

>>> re.match(r'(([A-Z][a-z]{,2})(\d*))+$', 'H2TeO4')
<_sre.SRE_Match object at 0x920f520>
>>> re.match(r'(([A-Z][a-z]{,2})(\d*))+$', 'H3PoooO5')
>>> 

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

>>> res = re.findall(r'([A-Z][a-z]{,2})(\d*)(?=(?:[A-Z][a-z]{,2}\d*|$))', s)
>>> res
[('C', '6'), ('H', '5'), ('Fe', '2'), ('I', '')]
>>> ''.join(''.join(i) for i in res) == s
True
0 голосов
/ 07 октября 2010

Вы можете сделать это не так много кода с помощью re.split - да, это правильно, re.split .

Вот документы :

Обратить вашу проблему: разделите ваш ввод с помощью шаблона разделителя, который соответствует действительному количеству атомов +.Имейте группу захвата так, чтобы строки разделителя были сохранены.Если входная строка верна, все неделитеры в результате будут пустыми строками.

>>> tests= (
... 'C6H5Fe2I',
... 'H2TeO4',
... 'H3PoooO5',
... 'C2tH6',
... 'Bad\n')
>>> import re
>>> pattern = r'([A-Z][a-z]{0,2}\d*)'
>>> for test in tests:
...     pieces = re.split(pattern, test)
...     print "\ntest=%r pieces=%r" % (test, pieces)
...     data = pieces[1::2]
...     rubbish = filter(None, pieces[0::2])
...     print "rubbish=%r data=%r" % (rubbish, data)
...

test='C6H5Fe2I' pieces=['', 'C6', '', 'H5', '', 'Fe2', '', 'I', '']
rubbish=[] data=['C6', 'H5', 'Fe2', 'I']

test='H2TeO4' pieces=['', 'H2', '', 'Te', '', 'O4', '']
rubbish=[] data=['H2', 'Te', 'O4']

test='H3PoooO5' pieces=['', 'H3', '', 'Poo', 'o', 'O5', '']
rubbish=['o'] data=['H3', 'Poo', 'O5']

test='C2tH6' pieces=['', 'C2', 't', 'H6', '']
rubbish=['t'] data=['C2', 'H6']

test='Bad\n' pieces=['', 'Bad', '\n']
rubbish=['\n'] data=['Bad']
>>>
0 голосов
/ 07 октября 2010

Мой ход без регулярного выражения:

tests= (
'C6H5Fe2I',   # this string should be matched successfully. Result: C6 H5 Fe2 I
'H2TeO4',     # this string should be matched successfully Result: H2 Te O4
'H3PoooO5',   # exception should be raised
'C2tH6')      # exception should be raised

def splitter(case):
    case, original = list(case), case
    while case:
        if case[0].isupper():
            result = case.pop(0)
        else:
            raise ValueError('%r is not capital letter in %s position %i.' %
                             (case[0], original, len(original)-len(case)))
        for count in range(2):
            if case and case[0].islower():
                result += case.pop(0)
            else:
                break
        for count in range(2):
            if case and case[0].isdigit():
                result += case.pop(0)
            else:
                break
        yield result

for testcase in tests:
    try:
        print tuple(splitter(testcase))
    except ValueError as e:
        print(e)
0 голосов
/ 07 октября 2010

для Валидации, пожалуйста, попробуйте, если вы используете .NET Framework

([A-Z][a-b]??[0-9]??)*

другой вариант

([A-Z][a-b]?[a-b]?[0-9]?[0-9]?)*
0 голосов
/ 07 октября 2010

Используйте этот шаблон

(([A-Z][a-z]{0,2})(\d*))+

Если он соответствует, отлично!Если нет, то справиться с этим.Я не вижу причин выдвигать исключение, если оно не совпадает.Вам нужно будет предоставить больше информации.

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