Regex 将整数数值间隔转换为正则表达式

Regex 将整数数值间隔转换为正则表达式,regex,algorithm,Regex,Algorithm,所以 我正在寻找关于这个问题的解决方案——如何将整数区间转换为正则表达式。假设我有两个数字,A和B。它们都是正整数,设为AA&&num

所以

我正在寻找关于这个问题的解决方案——如何将整数区间转换为正则表达式。假设我有两个数字,
A
B
。它们都是正整数,设为
A

现在,我正在寻找一种算法(可能是代码),它将生成一个正则表达式,该正则表达式将匹配
a
B
(包括边框)之间的数字。例如,我有
A=20
B=35
,那么正确的正则表达式是
^2[0-9]$| ^3[0-5]$
,因为只有数字20..35适合它

在一般情况下,当
A
类似于83724,而
B
类似于2854385时,就不那么明显了


upd。大多数情况下,这是一件令人好奇的事情。我知道执行此操作的最佳方法:返回结果:
A为什么在这种情况下使用正则表达式

我会这样做:

boolean isBetween=num>A&&num

(用Java编写的代码)

更简单的是,像您要求的那样的正则表达式可能非常庞大,在这种情况下使用它将毫无意义且效率低下

祝你好运


如果您确实坚持使用正则表达式来完成此任务,请参见,在启用详细模式的情况下运行正则表达式,它将向您解释作者的正则表达式是如何工作的。

正如其他人已经告诉您的,这不是一个很好的主意。它不会比只匹配所有整数然后过滤它们更快。但我还是会回答你的问题

根据间隔的大小,您可以让正则表达式引擎为您优化它,因此您只需输出一个
分隔的值列表。这可以用有限自动机理论的基本算法在算法上最小化

对于较大的间隔,这可能会占用大量内存。在这种情况下,您可以一次匹配A和B中不同长度的所有数字。在您的示例中,所有6-7位数字都很容易与
[0-9][1-9]{5,6}
匹配。现在剩下了边界情况,您可以通过递归方式创建边界情况(对于本例中的A端,我没有包括递归的基本情况):

  • 让我们成为一个
  • 设f为S的第一个数字,
    g=f+1
    ,n为
    (S的数字)-1
  • 为大于f的数字在正则表达式中添加一个段:
    [g-9][0-9]{n}
  • 为以f开头的数字添加一个段:
    f(从步骤2开始的递归调用,S=S的其余数字)
  • 因此,对于
    A=123
    我们最终会得到类似的结果(仅为“可读性”添加空格):

    我已经完成了(在PHP中):


    无论如何,非常感谢所有回答的人。

    我认为正则表达式不是解决您问题的最好、最简单的方法。是的,我知道直接比较会容易得多。就我而言,这是一个“安慰”的问题。例如@AlmaDoMundo。事实上,如果您成功地为此创建了一个正则表达式,您将失去一些舒适感。你最好使用正常范围检查。这就像问木匠如何使用螺丝刀敲入钉子。你也许能做到,但这是做这项工作的错误工具,木匠会嘲笑你。再一次,我意识到这一点。这不是一个关于我为什么要这样做的问题:p这是一个关于-我怎么做:p这充其量只是一个评论,而不是一个答案。@JamesWilliams-对我来说很好,谢谢(我试图理解,不是为了得到一个结果,所以详细模式非常棒)我很好奇你为什么决定使用递归。你可以非常直观地迭代:
    ([2-9][0-9]{2}|1[3-9][0-9]{1}|12[4-9]|123)
    递归对我来说更自然。但是你是对的,通过保留整个前缀,我们可以用相同的算法迭代。我还意识到我的递归算法给出了DFA,而rolius示例需要NFA来解决。如果这有任何区别,这取决于正则表达式引擎,但是一个简单的引擎不需要任何回溯来匹配我的模式。
    ([2-9][0-9]{2}) | (1(([3-9][0-9]{1}) | (2(([4-9]) | 3))) )
    
    class Converter
    {
        const REGEXP_OR     = '|';
        const REGEXP_START  = '^';
        const REGEXP_END    = '$';
    
        protected $sStart;
        protected $sEnd;
        function __construct($mStart, $mEnd=null)
        {
            if(is_array($mStart) && count($mStart)>1)
            {
                $this->sStart = (string)($mStart[0]);
                $this->sEnd   = (string)($mStart[1]);
            }
            else
            {
                $this->sStart = (string)($mStart);
                $this->sEnd   = (string)($mEnd);
            }
            if((int)($mStart)>(int)($mEnd))
            {
                $this->sStart = $this->sEnd = null;
            }
        }
    
        public function getRegexp()
        {
            return self::REGEXP_START.$this->_get_regexp_by_range($this->sStart, $this->sEnd).self::REGEXP_END;
        }
    
        protected function _get_regexp_by_range($sStart, $sEnd, $sOr=self::REGEXP_OR, $sFrom=self::REGEXP_START, $sTill=self::REGEXP_END)
        {
           if(!isset($sStart) || !isset($sEnd))
           {
               return null;
           }
           if((int)($sStart)>(int)($sEnd))
           {
              return null;
           }
           elseif($sStart==$sEnd)
           {
              return $sStart;
           }
           elseif(strlen($sEnd)>strlen($sStart))
           {
              $rgRegexp  = array($this->_get_regexp_by_range($sStart, str_repeat('9', strlen($sStart))));
              for($i=strlen($sStart)+1; $i<strlen($sEnd)-1; $i++)
              {
                 $rgRegexp[] = $this->_get_regexp_by_range('1'.str_repeat('0', $i), str_repeat('9', $i+1));
              }
              $rgRegexp[] = $this->_get_regexp_by_range('1'.str_repeat('0', strlen($sEnd)-1), $sEnd);
              return join($sTill.$sOr.$sFrom, $rgRegexp);
           }
           else
           {
              $rgRegexp   = array();
              for($iIntersect=0;$iIntersect<strlen($sStart);$iIntersect++)
              {
                 if($sStart[$iIntersect]!=$sEnd[$iIntersect])
                 {
                    break;
                 }
              }
              if($iIntersect)
              {
                 return join($sTill.$sOr.$sFrom, array_map(function($sItem) use ($iIntersect, $sStart)
                 {
                    return substr($sStart, 0, $iIntersect).$sItem;
                 }, explode($sTill.$sOr.$sFrom, $this->_get_regexp_by_range(substr($sStart, $iIntersect), substr($sEnd, $iIntersect)))));
              }
              else
              {
                 $rgRegexp = array($sStart);
                 for($iPos=strlen($sStart)-1; $iPos>0; $iPos--)
                 {
                    if($sStart[$iPos]+1<10)
                    {
                       $rgRegexp[]=substr($sStart, 0, $iPos).'['.($sStart[$iPos]+1).'-'.'9'.']'.str_repeat('[0-9]', strlen($sStart)-$iPos-1);
                    }
                 }
                 if(($sStart[0]+1)<($sEnd[0]-1))
                 {
                    $rgRegexp[]='['.($sStart[0]+1).'-'.($sEnd[0]-1).']'.str_repeat('[0-9]', strlen($sStart)-1);
                 }
                 elseif((int)($sStart[0])+1==(int)($sEnd[0])-1)
                 {
                    $rgRegexp[]=($sStart[0]+1).str_repeat('[0-9]', strlen($sStart)-1);
                 }
                 for($iPos=1; $iPos<strlen($sEnd); $iPos++)
                 {
                    if($sEnd[$iPos]-1>=0)
                    {
                      $rgRegexp[]=substr($sEnd,0, $iPos).'['.'0'.'-'.($sEnd[$iPos]-1).']'.str_repeat('[0-9]', strlen($sEnd)-$iPos-1);
                    }
                 }
                 $rgRegexp[]=$sEnd;
                 return join($sTill.$sOr.$sFrom, $rgRegexp);
              }
           }
        }
    }
    
    $sPattern = (new Converter('1', '1000000000'))->getRegexp();
    var_dump(
       preg_match('/'.$sPattern.'/', '10000000000'), 
       preg_match('/'.$sPattern.'/', '100000000'));