Python 正则表达式:从字符串中提取所有可能的字符类型,并根据示例自动创建正则表达式模式

Python RegEx: Extract all possible types of chars from string and automatically create a RegEx pattern based on sample

我想自动分析所有现有字符类型的字符串,并基于带有示例模板的列创建 RegEx 模式。
这样以后与此模式相关的任何字符串都可以仅通过允许的字符进行清理,然后与模式对齐。

例如样本可以是:

"A111AA1" - 表示所有可能的字符:只有字母和数字;模式应为:第一个字母,然后是 3 个数字,然后是 2 个字母和 1 个数字。

"11AA-111A" - 表示可能的字符:字母、数字、hyphen/dash;模式:2 位数字,2 个字母,破折号,3 位数字,1 个字母。

没有手动 if-else 硬编码是否可行?唯一模式可能 > 1000。

谢谢。

更新

关于提取字符串中所有可能的字符,我创建了以下函数。它使用模式中的现有(允许)字符创建 RegEx。
如果你知道更好的方法,请告诉我。

def extractCharsFromPattern(pattern: str) -> str:
    allowedChars = []
    
    # Convert string to set of chars
    pattern = ''.join(set(pattern))
    
    # Letters
    if re.findall(r"[a-zA-Z]", pattern):
        allowedChars.append("a-zA-Z")
        pattern = re.sub(r"[a-zA-Z]", "", pattern)
    # Digits
    if re.findall(r"[0-9]", pattern):
        allowedChars.append("0-9")
        pattern = re.sub(r"[0-9]", "", pattern)    
    # Special chars
    allowedChars.append(pattern)
    
    # Prepare in regex format
    allowedChars = "[" + "".join(allowedChars) + "]"
    
    return allowedChars

如果您的模式如此简单,那么您当然可以匹配它以获得正则表达式,例如:

patterns = ["A111AA1", "11AA-111A"]
for pattern in patterns:
    re_pattern = ''.join([r'\d' if c.isdigit() else r'[a-zA-Z]' if c.isalpha() else r'-' if c=='-' else '???' for c in pattern])
    print (pattern, '-->', re_pattern)

A111AA1   --> [a-zA-Z]\d\d\d[a-zA-Z][a-zA-Z]\d
11AA-111A --> \d\d[a-zA-Z][a-zA-Z]-\d\d\d[a-zA-Z]

根据您的评论,如果您只想要一个角色 class,您可以将其全部链接在一起。这是一个单行示例,但根据您的要求,您可以将它放在一个函数中:

>>> s="AA-22"
>>> r = ('['                                   # start of character class
  +  ('a-z' if re.search(r'[a-z]', s) else '') # have a lowercase?
  + ('A-Z' if re.search(r'[A-Z]', s) else '')  # have an uppercase?
  + ('0-9' if re.search(r'[0-9]', s) else '')  # have a number?
  + ('-' if re.search(r'-', s) else '')        # have a dash
  + ']'                                        # end of character class
  +  '{' + str(len(s)) + '}'                   # enforce a length?
)
# '[A-Z0-9-]{5}'
>>> re.search(r, "BB-44").group(0)
# 'BB-44'