3

我想要一个正则表达式来匹配一些包含字母和数字字符的文本。但我不希望它只匹配字母或数字。例如在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},即即使有更多或少于 8 个字符,它也可以匹配。

- 编辑 -

问题更多的是要了解是否有一种方法可以编写正则表达式,以便我可以组合 2 个模式(在本例中为[0-9][a-z])并确保匹配的字符串与这两个模式匹配,但每个集合匹配的字符数是可变的。eg 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
4

5 回答 5

4

尝试以下正则表达式:

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

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

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

注意:虽然 python 不是这种情况,但我观察到并非所有种类的工具都支持前瞻后瞻。因此,如果可能,我宁愿避免使用它们。

于 2013-10-08T18:30:31.350 回答
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']
于 2013-10-08T18:27:40.697 回答
2

不是最漂亮的正则表达式,但它有效:

\b[a-z\d]*(?:\d[a-z]|[a-z]\d)[a-z\d]*\b
于 2013-10-08T18:30:37.430 回答
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])是一个类似的前瞻,但检查数字。

于 2013-10-08T18:13:19.327 回答
0

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

import re
s = '[mytaskid: 3fee46d2]: STARTED at processing job number 10022001'
mo = re.search(':\s+(\w+)', s)
print mo.group(1)
于 2013-10-08T18:15:54.120 回答