如何检查正则表达式是否完全匹配字符串,即 - 字符串不包含任何额外字符?

时间:2010-10-07 07:29:32

标签: python regex exception-handling error-handling

我有两个问题:

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)第二个问题是,如果输入字符串错误,我应该提出什么样的异常。

谢谢Tomas

10 个答案:

答案 0 :(得分:4)

您可以使用以下几种不同的方法:

比较长度

  • 查找原始字符串的长度。
  • 求和匹配字符串的长度。
  • 如果两个号码不同,则有未使用的字符。

请注意,如果您想避免解析字符串两次,也可以将此方法与现有代码结合使用,而不是将其作为额外步骤。

整个字符串的正则表达式

您可以检查此正则表达式是否与整个字符串匹配:

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

(Rubular)

<强>标记化

您可以使用以下正则表达式来标记原始字符串:

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

然后检查每个标记,看它是否与原始正则表达式匹配。

答案 1 :(得分:3)

  

大写字母,后跟0,1或2   小写字母,后跟0或更多   编号

好的。

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

此处的差异是(foo)+中的额外分组^$,允许您捕获模式 foo N次。

没有全球旗帜?猜猜你必须再次将该正则表达式的结果拆分为该模式。

答案 2 :(得分:2)

你需要稍微不同的正则表达式:

^([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

答案 3 :(得分:2)

您是否需要提取每个要处理的零件,或者只是匹配输入验证?如果您只需要匹配验证,请尝试^([A-Z][a-z]{0,2}\d*)+$

答案 4 :(得分:2)

>>> 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

要比上面的代码更清楚地回答您的第二个问题:如果参数的类型正确但值不正确,则使用ValueError。因此,对于使用正则表达式的函数,它显然是您可以选择的最佳函数。

答案 5 :(得分:0)

使用此模式

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

如果匹配,太棒了!如果没有,那就处理吧。如果不匹配,我认为没有理由提出异常。你必须提供更多信息。

答案 6 :(得分:0)

验证请试试 如果您使用的是.NET Framework

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

其他明智的

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

答案 7 :(得分:0)

我没有正则表达式:

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)

答案 8 :(得分:0)

您可以使用 re.split 在不多的代码中执行此操作 - 是的,这是正确的, re.split

以下是the docs

反转您的问题:使用与有效原子+计数匹配的分隔符模式拆分输入。有一个捕获组,以便保留分隔符字符串。如果输入字符串有效,则结果中的非分隔符将全部为空字符串。

>>> 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']
>>>

答案 9 :(得分:0)

通过匹配输入字符串中的模式并用空字符串 ('') 替换(替换)匹配项,这可能是最简单的方法。现在,如果整个字符串变为空,那么它就是一个完整的匹配! (否则,如果有任何剩余,则不是完整匹配。)

import re

pattern = r'([A-Z][a-z]{0,2})(\d*)'

input_text = "C6H5Fe2I" # Some input text
output = re.sub(pattern, '', input_text)

if output == '':
    print("[INFO] COMPLETE MATCH!")
    print("[FINDINGS]", re.findall(pattern, input_text))
else:
    print("[INFO] NOT A COMPLETE MATCH.")