patterns = {}
patterns[1] = re.compile("[A-Z]\d-[A-Z]\d")
patterns[2] = re.compile("[A-Z]\d-[A-Z]\d\d")
patterns[3] = re.compile("[A-Z]\d\d-[A-Z]\d\d")
patterns[4] = re.compile("[A-Z]\d\d-[A-Z]\d\d\d")
patterns[5] = re.compile("[A-Z]\d\d\d-[A-Z]\d\d\d")
patterns[6] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d")
patterns[7] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d")
patterns[8] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d")
patterns[9] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d\d")
patterns[10] = re.compile("[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d")
def matchFound(toSearch):
for items in sorted(patterns.keys(), reverse=True):
matchObject = patterns[items].search(toSearch)
if matchObject:
return items
return 0
然后我使用以下代码来查找匹配项:
while matchFound(toSearch) > 0:
我有10种不同的正则表达式,但我觉得它们可以被一个写得很好,更优雅的正则表达式所取代。你们认为这有可能吗?
编辑:忘记两次表达:
patterns[11] = re.compile("[A-Z]\d-[A-Z]\d\d\d")
patterns[12] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d\d")
EDIT2:我最终得到了以下内容。我意识到我可以获得额外的结果,但我不认为它们在我正在解析的数据中是可能的。
patterns = {}
patterns[1] = re.compile("[A-Z]{1,2}\d-[A-Z]{1,2}\d{1,3}")
patterns[2] = re.compile("[A-Z]{1,2}\d\d-[A-Z]{1,2}\d{2,3}")
patterns[3] = re.compile("[A-Z]{1,2}\d\d\d-[A-Z]{1,2}\d\d\d")
答案 0 :(得分:4)
Sean Bright为您提供了所需的答案。这里只是一个一般提示:
Python有很棒的文档。在这种情况下,您可以使用“help”命令阅读它:
import re
help(re)
如果你阅读了帮助,你会看到:
{m,n} Matches from m to n repetitions of the preceding RE.
使用Google也很有帮助。 “Python正则表达式”为我找到了这些链接:
http://docs.python.org/library/re.html
http://docs.python.org/howto/regex.html
两者都值得一读。
答案 1 :(得分:4)
Josh Caswell指出,Sean Bright的答案将比原始组更多地输入。对不起,我没想到这个。 (将来再详细说明你的问题可能会更好。)
所以你的基本问题是正则表达式无法计算。但是我们仍然可以用非常灵巧的方式在Python中解决这个问题。首先,我们制作一个与您的任何合法输入相匹配的模式,但也会匹配您想要拒绝的模式。
接下来,我们定义一个使用该模式的函数,然后检查匹配对象,并计算以确保匹配的字符串符合长度要求。
import re
_s_pat = r'([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})'
_pat = re.compile(_s_pat)
_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)])
def check_match(s):
m = _pat.search(s)
try:
a0, n0, a1, n1 = m.groups()
if len(a0) != len(a1):
return False
if not (len(n0), len(n1)) in _valid_n_len:
return False
return True
except (AttributeError, TypeError, ValueError):
return False
以上是对上述代码的一些解释。
首先我们使用原始字符串来定义模式,然后我们预编译模式。我们可以将文字字符串填充到re.compile()
的调用中,但我喜欢有一个单独的字符串。我们的模式有四个不同的部分用括号括起来;这些将成为“匹配组”。有两个匹配组匹配字母字符,两个匹配组匹配数字。这个模式将匹配您想要的所有内容,但不会排除您不想要的内容。
接下来,我们声明一个set
,它具有数字的所有有效长度。例如,第一组数字可以是1位数字,第二组可以是2位数字;这是(1,2)
(tuple
值)。集合是指定我们想要合法的所有可能组合的好方法,同时仍然能够快速检查给定的一对长度是否合法。
函数check_match()
首先使用模式匹配字符串,返回绑定到名称m
的“匹配对象”。如果搜索失败,m
可能会设置为None
。我没有明确测试None
,而是使用try
/ except
块;回想起来,测试None
可能会更好。对不起,我不是故意混淆。但是try
/ except
块是一种非常简单的方法来包装并使其非常可靠,所以我经常将它用于这样的事情。
最后,check_match()
将匹配组解包为四个变量。两个alpha组是a0和a1,两个数字组是n0和n1。然后它检查长度是否合法。据我所知,规则是alpha组需要相同的长度;然后我们构建tuple
个数字组长度,并检查tuple
是否在我们set
的有效tuple
中。
以上是略有不同的版本。也许你会更喜欢它。
import re
# match alpha: 1 or 2 capital letters
_s_pat_a = r'[A-Z]{1,2}'
# match number: 1-3 digits
_s_pat_n = r'\d{1,3}'
# pattern: four match groups: alpha, number, alpha, number
_s_pat = '(%s)(%s)-(%s)(%s)' % (_s_pat_a, _s_pat_n, _s_pat_a, _s_pat_n)
_pat = re.compile(_s_pat)
# set of valid lengths of number groups
_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)])
def check_match(s):
m = _pat.search(s)
if not m:
return False
a0, n0, a1, n1 = m.groups()
if len(a0) != len(a1):
return False
tup = (len(n0), len(n1)) # make tuple of actual lengths
if not tup in _valid_n_len:
return False
return True
注意:看起来有效长度的规则实际上很简单:
if len(n0) > len(n1):
return False
如果该规则适合您,您可以摆脱集合和元组的东西。嗯,我会把变量名称缩短一点。
import re
# match alpha: 1 or 2 capital letters
pa = r'[A-Z]{1,2}'
# match number: 1-3 digits
pn = r'\d{1,3}'
# pattern: four match groups: alpha, number, alpha, number
p = '(%s)(%s)-(%s)(%s)' % (pa, pn, pa, pn)
_pat = re.compile(p)
def check_match(s):
m = _pat.search(s)
if not m:
return False
a0, n0, a1, n1 = m.groups()
if len(a0) != len(a1):
return False
if len(n0) > len(n1):
return False
return True
答案 2 :(得分:3)
Josh至少可以减少RE的数量。
但是你也可以选择比允许的更宽的RE,然后另外检查是否满足所有条件。如
pattern = re.compile("([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})")
然后
matchObject = pattern.search(toSearch)
if matchObject and <do something with the length of the groups, comparing them)>:
return <stuff>
但即使由于任何原因而无效,也有办法改善:
patterns = tuple(re.compile(r) for r in (
"[A-Z]\d-[A-Z]\d{1,2}",
"[A-Z]\d\d-[A-Z]\d{2,3}",
"[A-Z]\d\d\d-[A-Z]\d\d\d",
"[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,2}",
"[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}",
"[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d",
)
def matchFound(toSearch):
for pat in reversed(patterns):
matchObject = pat.search(toSearch)
if matchObject:
return items # maybe more useful?
return None
答案 3 :(得分:1)
以Sean(现在显然已删除)的答案为基础,您可以减少模式的数量。由于数字匹配长度组合的限制(即,如果m
在第一个位置,至少m
并且在第二个位置不超过3)我不确定你能得到它归结为一个:
"[A-Z]\d-[A-Z]\d{1,3}"
"[A-Z]\d\d-[A-Z]\d{2,3}"
"[A-Z]\d\d\d-[A-Z]\d\d\d"
"[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,3}"
"[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}"
"[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d"
这使用{m,n}
repeat qualifier syntax,它指定前一个匹配至少重复m
但不超过n
次。您还可以指定一个数字n
;然后匹配必须完全n
次成功:
"[A-Z]{2}\d-[A-Z]{2}\d{2,3}"