我需要创建一个正则表达式来验证字符串。字符串只能包含几个字符,每个字符只能重复几次。
正则表达式应检查以下条件。
我知道这可以通过字符串函数来实现。但是我正在尝试使用正则表达式。
在此方面的任何帮助都将受到高度赞赏。
答案 0 :(得分:4)
同样,出于性能考虑,最好的方法是使用Python本机字符串操作。
我会这样写:
lim=(('a',2),('b',3),('c',3),('d',1),('e',1))
results={}
for s in [list_of_many_strings]:
results[s]=bool(not(set(s)-set('abcde'))) and (not any(s.count(c)>x for c,x in lim))
这依靠str.count(sub[, start[, end]])来计算字符串中子字符串的出现,并依靠any function来测试是否满足任何条件。
由于您对性能感兴趣,因此可以确定使用timeit
处理100,000个字符串可能要花费多长时间:
import re
def f1(li):
results={}
lim=(('a',2),('b',3),('c',3),('d',1),('e',1))
for s in li:
results[s]=bool(not(set(s)-set('abcde'))) and (not any(s.count(c)>x for c,x in lim))
return results
def f2(li):
pat=re.compile(r'^a{0,2}b{0,3}c{0,3}d{0,1}e{0,1}$')
results={}
for s in li:
results[s]=True if pat.search(''.join(sorted(s))) else False
return results
def f3(li):
pat=re.compile(r'^(?!.*[^a-e])(?!(?:.*a){3})(?!(?:.*b){4})(?!(?:.*c){4})(?!(?:.*d){2})(?!(?:.*e){2}).+')
results={}
for s in li:
results[s]=True if pat.search(s) else False
return results
if __name__=='__main__':
import timeit
import random
s='abcdeabcdebc'
li=[''.join(random.sample(s,8)) for _ in range(100000)]
print(f1(li)==f2(li)==f3(li))
for f in (f1,f2,f3):
print(" {:^10s}{:.4f} secs".format(f.__name__, timeit.timeit("f(li)", setup="from __main__ import f, li", number=10)))
在我的计算机上,需要:
True
f1 0.8519 secs
f2 1.1235 secs
f3 1.3070 secs
答案 1 :(得分:3)
可以通过以下方式构造检查多个条件的正则表达式:
^
-源字符串的开头。.+
-如果先前的所有查找均成功,则匹配整个(通常
非空)源字符串。如果正向或负向查找都指向一个字符
任意位置,它应以.*
开头,
指出在我们实际检查之前,可能会发生任何
任何(其他)字符的数量,可能没有。
您的案件实际上仅包含“禁止”条件,说明 这是不允许的:
(?!.*[^a-e])
-除a-e
以外的任何字符。(?!(?:.*a){3})
-a
出现3次(或更多)。(?!(?:.*b){4})
-b
出现4次(或更多)。(?!(?:.*c){4})
-c
出现4次(或更多)。(?!(?:.*d){2})
-d
出现2次(或更多)。(?!(?:.*e){2})
-e
出现2次(或更多)。因此整个正则表达式应为:
^(?!.*[^a-e])(?!(?:.*a){3})(?!(?:.*b){4})(?!(?:.*c){4})(?!(?:.*d){2})(?!(?:.*e){2}).+
答案 2 :(得分:2)
如果您的字符串已经排序,例如所有a
字符已经在所有b
字符的前面,依此类推,则像这样的简单正则表达式将起作用:
r'^a{0,2}b{0,3}c{0,3}d{0,1}e{0,1}$'
如果字符串中的字符未排序,那么,请先对它们进行排序=)
并且如果您的“最多可以出现2次”的含义是1或2次(如我所料,不是0、1或2),则将0
中的所有1
替换为{ reg.expression。
答案 3 :(得分:1)
由于您使用的是熊猫,因此最好使用矢量化操作。尽管我不愿意检查,但这些应该更快。这是一种可能的方法,熊猫或numpy专家可能有更好的方法:
import random
import pandas as pd
s = 'abcdeabcdebc'
df = pd.DataFrame({'s': [''.join(random.sample(s, 8)) for _ in range(100000)]})
count = df.s.str.count
df['valid'] = ((count('[^a-e]') == 0) &
(count('a') <= 2) &
(count('b') <= 3) &
(count('c') <= 3) &
(count('d') <= 1) &
(count('e') <= 1))
print(df.head())
示例输出:
s valid
0 cacbdbec True
1 cabdceab True
2 bbdcdabe False
3 ecaadbce False
4 ebabcdad False