我有两个问题:
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
答案 0 :(得分:4)
您可以使用以下几种不同的方法:
比较长度
请注意,如果您想避免解析字符串两次,也可以将此方法与现有代码结合使用,而不是将其作为额外步骤。
整个字符串的正则表达式
您可以检查此正则表达式是否与整个字符串匹配:
^([A-Z][a-z]{0,2}\d*)*$
<强>标记化强>
您可以使用以下正则表达式来标记原始字符串:
[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.")