如何判断一个正则表达式是否与另一个正则表达式的子集匹配?

时间:2011-06-15 19:47:42

标签: python regex

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

['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>

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

如果仍然不清楚,请告诉我。

7 个答案:

答案 0 :(得分:11)

我认为 - 从理论上讲 - 判断regexp A是否匹配regexp B匹配的子集,算法可以:

  1. 计算B以及“union”A|B的最小确定性有限自动机。
  2. 检查两个DFA是否相同。当且仅当A匹配B匹配的子集时才是这样。
  3. 然而,在实践中这可能是一个重要的项目。有一些解释如Constructing a minimum-state DFA from a Regular Expression但他们只倾向于考虑数学上纯粹的正则表达式。为了方便起见,您还必须处理Python添加的扩展。此外,如果任何扩展导致语言不规则(我不确定是否是这种情况),您可能无法处理这些。

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

答案 1 :(得分:6)

除了antinome's answer

许多不属于基本正则表达式定义的构造仍然是常规的,并且可以在解析正则表达式后进行转换(使用真正的解析器,因为正则表达式的语言本身不是常规的):(x?)(x|)(x+)(xx*),字符类如[a-d]到相应的联合(a|b|c|d)等等。所以可以使用这些结构并仍然测试是否有一个正则表达式使用antinome提到的DFA比较匹配其他正则表达式的子集。

某些构造(如后引用)不是常规构造,也不能用NFA或DFA表示。

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

答案 2 :(得分:6)

使用两个正则表达式“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 :(得分:1)

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

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

答案 4 :(得分:1)

你应该按照这些方针做点什么:

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

正则表达式必须定义字符串应该是什么样子。如果你想匹配一个开头的方括号,后跟一个从b到x的字母,然后是一个破折号,然后是另一个从b到x的字母,最后是一个结束的方括号,上面的解决方案应该有效。

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

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我认为需要做一些澄清:

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

'(?<! )[a-z52]+' 模式

rA是类 RegexObject 的实例,其类型为 &lt; * 键入'_sre.SRE_Pattern'&gt; *

就我个人而言,我专门为这类对象使用术语 正则表达式 ,而不是模式。

注意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 类的实例,其类型为 *&lt;输入'_sre.SRE_Match'&gt; *


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

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