regEx:匹配两组字符

时间:2013-10-08 18:01:21

标签: python regex

我希望regEx匹配一些包含字母和数字字符的文本。但我不希望它只匹配alpha或数字。 例如。在python:

s = '[mytaskid: 3fee46d2]: STARTED at processing job number 10022001'
#               ^^^^^^^^ <- I want something that'll only match this part.
import re
rr = re.compile('([0-9a-z]{8})')
print 'sub=', rr.sub('########', s)
print 'findall=', rr.findall(s)

生成以下输出:

sub= [########: ########]: STARTED at ########ng job number ########
findall= ['mytaskid', '3fee46d2', 'processi', '10022001']

我希望它是:

sub= [mytaskid: ########]: STARTED at processing job number 10022001
findall= ['3fee46d2']

任何想法......? 在这种情况下,它总是只有8个字符,如果有一个没有{8}的regEx会更加精彩,即即使有多于或少于8个字符。

- 编辑 -

问题更多的是要了解是否有办法编写一个regEx,这样我就可以组合2个模式(在本例中为[0-9][a-z])并确保匹配的字符串匹配两种模式,但从每组匹配的字符数是可变的。例如。 s也可以

s = 'mytaskid 3fee46d2 STARTED processing job number 10022001'

- 回答 -

感谢大家的答案,所有人都给了我想要的东西,所以每个人都获得+1,第一个回答得到了接受的答案。虽然杰里解释得最好。 :)

如果有人是表演的坚持者,没有什么可供选择的,他们都是一样的。

s = '[mytaskid: 3fee46d2]: STARTED at processing job number 10022001'
#               ^^^^^^^^ <- I want something that'll only match this part.
def testIt(regEx):
    from timeit import timeit
    s = '[mytaskid: 3333fe46d2]: STARTED at processing job number 10022001'
    assert (re.sub('\\b(?=[a-z0-9]*[0-9])[a-z0-9]*[a-z][a-z0-9]*\\b', '########', s) ==
            '[mytaskid: ########]: STARTED at processing job number 10022001'), '"%s" does not work.' % regEx
    print 'sub() with \'', regEx, '\': ', timeit('rr.sub(\'########\', s)', number=500000, setup='''
import re
s = '%s'
rr = re.compile('%s')
''' % (s, regEx)
    )
    print 'findall() with \'', regEx, '\': ', timeit('rr.findall(s)', setup='''
import re
s = '%s'
rr = re.compile('%s')
''' % (s, regEx)
    )

testIt('\\b[0-9a-z]*(?:[a-z][0-9]|[0-9][a-z])[0-9a-z]*\\b')
testIt('\\b[a-z\d]*(?:\d[a-z]|[a-z]\d)[a-z\d]*\\b')
testIt('\\b(?=[a-z0-9]*[0-9])[a-z0-9]*[a-z][a-z0-9]*\\b')
testIt('\\b(?=[0-9]*[a-z])(?=[a-z]*[0-9])[a-z0-9]+\\b')

制备:

sub() with ' \b[0-9a-z]*(?:[a-z][0-9]|[0-9][a-z])[0-9a-z]*\b ':  0.328042736387
findall() with ' \b[0-9a-z]*(?:[a-z][0-9]|[0-9][a-z])[0-9a-z]*\b ':  0.350668751542
sub() with ' \b[a-z\d]*(?:\d[a-z]|[a-z]\d)[a-z\d]*\b ':  0.314759661193
findall() with ' \b[a-z\d]*(?:\d[a-z]|[a-z]\d)[a-z\d]*\b ':  0.35618526928
sub() with ' \b(?=[a-z0-9]*[0-9])[a-z0-9]*[a-z][a-z0-9]*\b ':  0.322802906619
findall() with ' \b(?=[a-z0-9]*[0-9])[a-z0-9]*[a-z][a-z0-9]*\b ':  0.35330467656
sub() with ' \b(?=[0-9]*[a-z])(?=[a-z]*[0-9])[a-z0-9]+\b ':  0.320779061371
findall() with ' \b(?=[0-9]*[a-z])(?=[a-z]*[0-9])[a-z0-9]+\b ':  0.347522144274

5 个答案:

答案 0 :(得分:4)

尝试以下正则表达式:

\b[0-9a-z]*(?:[a-z][0-9]|[0-9][a-z])[0-9a-z]*\b

这将匹配包含数字后跟字母的单词,反之亦然。

因此,它将涵盖一整套包含至少一位数字和一个字母的单词。

注意:虽然不是python的情况,但我发现并非所有类型的工具都支持 lookahead lookbehind 。所以我更愿意尽可能避免它们。

答案 1 :(得分:2)

您需要使用前瞻(?=...)

这个匹配[123]和[abc]中至少有一个的所有单词。

>>> re.findall('\\b(?=[abc321]*[321])[abc321]*[abc][abc321]*\\b', '  123abc 123 abc')
['123abc']

这样你就可以对同一个字符串的约束进行AND。

>>> help(re) 
(?=...)  Matches if ... matches next, but doesn't consume the string.

另一种方法是将它接地并说:用[abc]中的一个和[123]中的一个表示字符串中至少有[123] [abc]或[abc] [123]在

>>> re.findall('\\b[abc321]*(?:[abc][123]|[123][abc])[abc321]*\\b', '  123abc 123 abc')
['123abc']

答案 2 :(得分:2)

不是最美丽的正则表达式,但它有效:

\b[a-z\d]*(?:\d[a-z]|[a-z]\d)[a-z\d]*\b

答案 3 :(得分:1)

如果格式每次都相同,那就是:

[########: ########]: STARTED at ########ng job number ########

您可以使用:

([^\]\s]+)\]

使用re.findallre.search,如果您使用.group(1),则会获得re.search

[^\]\s]+是一个否定的类,将匹配除空格(和系列)或右方括号之外的任何字符。

正则表达式基本上会查找字符(]或空格除外)直到结束方括号。


如果要匹配包含字母和数字字符的任何字符串,则需要前瞻:

\b(?=[0-9]*[a-z])(?=[a-z]*[0-9])[a-z0-9]+\b

像这样使用:

result = re.search(r'\b(?=[0-9]*[a-z])(?=[a-z]*[0-9])[a-z0-9]+\b', text, re.I)

re.I用于忽略。

\b是单词边界,仅匹配“单词”字符和“非单词”字符(或字符串的开头/结尾)。

(?=[0-9]*[a-z])是一个积极的前瞻,并确保要匹配的部分中至少有1个alpha。

(?=[a-z]*[0-9])是类似的前瞻,但会检查数字。

答案 4 :(得分:0)

您可以使用更具体的正则表达式并跳过findall。

import re
s = '[mytaskid: 3fee46d2]: STARTED at processing job number 10022001'
mo = re.search(':\s+(\w+)', s)
print mo.group(1)