【问题标题】:How to tell if one regular expression matches a subset of another regular expression?如何判断一个正则表达式是否匹配另一个正则表达式的子集?
【发布时间】:2011-06-15 19:47:41
【问题描述】:

我只是想知道是否可以使用一个正则表达式来匹配另一个,这是某种:

['a-z'].match(['b-x'])
True

['m-n'].match(['0-9'])
False

这种事情完全可以用正则表达式吗?我在 python 中工作,所以任何特定于re 模块实现的建议都会有所帮助,但我会采取任何关于正则表达式的方法。

编辑:好的,一些澄清显然是有序的!我绝对知道正常的匹配语法看起来像这样:

expr = re.compile(r'[a-z]*')
string = "some words"
expr.match(string)
<sRE object blah blah>

但我想知道正则表达式是否能够匹配我试图在上面解释的非语法正确版本中的其他不太具体的表达式,来自 b-x 的任何字母总是任何字母的子集(匹配)从 a-z。我只是通过尝试知道这不是你可以通过调用一个编译表达式的匹配到另一个编译表达式来做的事情,但问题仍然存在:这可能吗?

如果还不清楚,请告诉我。

【问题讨论】:

  • 你的意思是一个正则表达式会提供与另一个相同或子集的匹配吗?
  • 与 re 匹配有两种不同的形式:re.match(regex, string) 或 re.compile(regex).match(string)。您能否更正您提供的代码,因为您想要实现的目标尚不清楚。
  • 每个正则表达式匹配一组字符串(一些正则表达式的无限集)。你想知道这两组是否重叠吗?或者第二组是否是第一组的子集? (我不知道该怎么做,但我认为需要澄清。)
  • 这个库声称支持数学正则表达式,这意味着你可以对它们进行联合:leafstorm/lexington

标签: python regex


【解决方案1】:

我认为——理论上——判断正则表达式 A 是否匹配正则表达式 B 匹配的子集,算法可以:

  1. 计算B 和“联合”A|B 的最小确定性有限自动机。
  2. 检查两个 DFA 是否相同。当且仅当 A 匹配 B 匹配的子集时,这是正确的。

但是,在实践中这样做可能是一个重大项目。有诸如Constructing a minimum-state DFA from a Regular Expression 之类的解释,但它们只倾向于考虑数学上纯正则表达式。为了方便起见,您还必须处理 Python 添加的扩展。此外,如果任何扩展导致语言不规则(我不确定是否是这种情况),您可能无法处理这些扩展。

但是你想做什么?也许有更简单的方法...?

【讨论】:

【解决方案2】:

“antinome”使用两个正则表达式验证帖子:55* 和 5*:

REGEX_A: 55* [这匹配“5”、“55”、“555”等,不匹配“4”、“54”等]

REGEX_B: 5* [这匹配“”、“5”、“55”、“555”等,不匹配“4”、“54”等]

[这里我们假设 55* 不是隐含的 .55.* 而 5* 不是 .5.* - 这就是为什么 5* 不是匹配4]

REGEX_A 可以有如下的 NFA:

  {A}--5-->{B}--epsilon-->{C}--5-->{D}--epsilon-->{E}
           {B} -----------------epsilon --------> {E} 
                          {C} <--- epsilon ------ {E}

REGEX_B 可以有如下的 NFA:

  {A}--epsilon-->{B}--5-->{C}--epsilon-->{D}
  {A} --------------epsilon -----------> {D} 
                 {B} <--- epsilon ------ {D}

现在我们可以推导出 (REGEX_A|REGEX_B) 的 NFA * DFA 如下:

  NFA:
  {state A}  ---epsilon --> {state B} ---5--> {state C} ---5--> {state D}
                                              {state C} ---epsilon --> {state D} 
                                              {state C} <---epsilon -- {state D}
  {state A}  ---epsilon --> {state E} ---5--> {state F}
                            {state E} ---epsilon --> {state F} 
                            {state E} <---epsilon -- {state F}

  NFA -> DFA:

       |   5          |  epsilon*
   ----+--------------+--------
    A  |  B,C,E,F,G   |   A,C,E,F
    B  |  C,D,E,F     |   B,C,E,F
    c  |  C,D,E,F     |   C
    D  |  C,D,E,F,G   |   C,D,E,F
    E  |  C,D,E,F,G   |   C,E,F
    F  |  C,E,F,G     |   F
    G  |  C,D,E,G     |   C,E,F,G

                    5(epsilon*)
    -------------+---------------------
              A  |  B,C,E,F,G 
      B,C,E,F,G  |  C,D,E,F,G 
      C,D,E,F,G  |  C,D,E,F,G 

    Finally the DFA for (REGEX_A|REGEX_B) is:
         {A}--5--->{B,C,E,F,G}--5--->{C,D,E,F,G}
                                     {C,D,E,F,G}---5--> {C,D,E,F,G}

         Note: {A} is start state and {C,D,E,F,G} is accepting state. 

REGEX_A (55*) 的 DFA 同样是:

       |   5    |  epsilon*
   ----+--------+--------
    A  | B,C,E  |   A
    B  | C,D,E  |   B,C,E
    C  | C,D,E  |   C
    D  | C,D,E  |   C,D,E
    E  | C,D,E  |   C,E


            5(epsilon*)
   -------+---------------------
       A  |  B,C,E  
   B,C,E  |  C,D,E
   C,D,E  |  C,D,E

    {A} ---- 5 -----> {B,C,E}--5--->{C,D,E}
                                    {C,D,E}--5--->{C,D,E}
Note: {A} is start state and {C,D,E} is accepting state

REGEX_B (5*) 的 DFA 同样是:

       |   5    |  epsilon*
   ----+--------+--------
    A  | B,C,D  |   A,B,D
    B  | B,C,D  |   B
    C  | B,C,D  |   B,C,D
    D  | B,C,D  |   B,D


            5(epsilon*)
   -------+---------------------
       A  |  B,C,D  
   B,C,D  |  B,C,D

    {A} ---- 5 -----> {B,C,D}
                      {B,C,D} --- 5 ---> {B,C,D}
Note: {A} is start state and {B,C,D} is accepting state

结论:

DFA of REGX_A|REGX_B identical to DFA of REGX_A 
      -- implies REGEX_A is subset of REGEX_B
DFA of REGX_A|REGX_B is NOT identical to DFA of REGX_B 
      -- cannot infer about either gerexes.

【讨论】:

    【解决方案3】:

    除了antinome's answer:

    许多不属于基本正则表达式定义的结构仍然是正则的,并且可以在解析正则表达式后进行转换(使用真正的解析器,因为正则表达式的语言本身不是正则):(x?) to @ 987654324@,(x+) 到 (xx*),像 [a-d] 这样的字符类到它们相应的联合 (a|b|c|d) 等。因此,可以使用这些构造,并且仍然使用提到的 DFA 比较来测试一个正则表达式是否匹配另一个正则表达式的子集通过反转录组。

    一些结构,如反向引用,不是正则的,不能用 NFA 或 DFA 表示。

    即使是测试带有反向引用的正则表达式是否与特定字符串匹配的看似简单的问题也是 NP-complete (http://perl.plover.com/NPC/NPC-3COL.html)。

    【讨论】:

    • 允许反向引用可能会使所述问题无法确定,但我没有证据证明这一点。
    【解决方案4】:
    pip3 install https://github.com/leafstorm/lexington/archive/master.zip
    python3
    >>> from lexington.regex import Regex as R
    >>> from lexington.regex import Null
    >>> from functools import reduce
    >>> from string import ascii_lowercase, digits
    >>> a_z = reduce(lambda a, b: a | R(b), ascii_lowercase, Null)
    >>> b_x = reduce(lambda a, b: a | R(b), ascii_lowercase[1:-2], Null)
    >>> a_z | b_x == a_z
    True
    >>> m_n = R("m") | R("n")
    >>> zero_nine = reduce(lambda a, b: a | R(b), digits, Null)
    >>> m_n | zero_nine == m_n
    False
    

    还使用 Python 2 成功测试。另请参阅 how to do it with a different library。

    或者,pip3 install https://github.com/ferno/greenery/archive/master.zip 和:

    from greenery.lego import parse as p
    a_z = p("[a-z]")
    b_x = p("[b-x]")
    assert a_z | b_x == a_z
    m_n = p("m|n")
    zero_nine = p("[0-9]")
    assert not m_n | zero_nine == m_n
    

    【讨论】:

      【解决方案5】:

      您应该按照以下方式做一些事情:

      re.match("\[[b-x]-[b-x]\]", "[a-z]")
      

      正则表达式必须定义字符串的外观。如果你想匹配一个左方括号,后跟一个从 b 到 x 的字母,然后是一个破折号,然后是另一个从 b 到 x 的字母,最后是一个右方括号,上面的解决方案应该可以工作。

      如果您打算验证正则表达式是否正确,您应该考虑测试它是否可以编译。

      【讨论】:

      • 匹配实际的表达式字符串太hacky(每个表达式都需要手动工作),我宁愿使用一个实现真正正则表达式的库,就像我的回答一样。
      【解决方案6】:

      正则表达式的字符串表示形式是可能的,因为任何字符串都可以与正则表达式匹配,但不能与re.compile 返回的编译版本匹配。不过,我看不出这有什么用。此外,它采用不同的语法。

      编辑:您似乎正在寻找检测language defined by an RE 是否是另一个RE 的子集的能力。是的,我认为这是可能的,但不,Python 的 re 模块没有做到这一点。

      【讨论】:

      • 我认为 OP 在这里的想法是“模式平等”,尽管从给出的例子来看,OP 认为 True 并不是真正的平等,因为第二个模式匹配 第一个的子集。
      【解决方案7】:

      我认为需要澄清一下:

      .

      rA = re.compile('(?<! )[a-z52]+')
      

      '(?&lt;! )[a-z52]+' 是一个模式

      rA 是 RegexObject 类的实例,其类型为 *type ' _sre.SRE_Pattern' >* 。

      我个人使用术语 regex 专门用于此类对象,而不是用于模式。

      注意rB = re.compile(rA) 也是可能的,它产生相同的对象(id(rA) == id(rB) 等于 True)


      ch = 'lshdgbfcs luyt52uir bqisuytfqr454'
      x = rA.match(ch) 
      # or
      y = rA.search(ch)
      

      x 和 y 是 MatchObject 类的实例,其类型为 **


      .

      也就是说,您想知道是否有办法确定一个正则表达式 rA 是否可以匹配另一个正则表达式 rB 匹配的所有字符串,而 rB 仅匹配 rA 匹配的所有字符串的子集。

      我认为这种方式不存在,无论理论上还是实践上。

      【讨论】:

      • 如果您将自己限制在实际的数学正则表达式中,它在理论和实践中确实有效!看我的回答!
      猜你喜欢
      • 2013-09-14
      • 2021-11-27
      • 2010-10-04
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多