3

所以,

我正在寻找有关该问题的解决方案 - 如何将整数间隔转换为正则表达式。假设我有两个数字,A并且B。它们都是正整数,让A < B

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

在常见的情况下,什么时候A是 83724 和B什么时候是 28543485 这不是那么明显,但是。

更新。大多数情况下,这是一个好奇心问题。我知道最好的方法:返回结果:A<=X && X<=B

4

3 回答 3

4

为什么在这种情况下使用正则表达式?

我会这样做:

boolean isBetween = num > A && num < B;

(用Java编写的代码)

更容易的是,像您所要求的那样的正则表达式可能很大,在这种情况下使用它将毫无意义且效率低下。

祝你好运。

如果你真的坚持使用 RegEx 来完成这项任务,请参阅这个网站,在详细模式下运行 regex,它将向你解释作者的 RegEx 是如何工作的。

于 2013-08-22T07:39:13.137 回答
2

正如其他人已经告诉你的那样,这不是一个好主意。它不会比仅匹配所有整数并随后过滤它们更快。但无论如何我都会回答你的问题。

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

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

  1. 设 S 为 A。
  2. 设 f 为 S 的第一位g=f+1, 和 n 为(digits of S)-1
  3. 为大于 f 的数字在正则表达式中添加一个段:[g-9][0-9]{n}
  4. 为以 f 开头的数字添加一个段:f(recursive call starting from step 2, with S=the rest of digits of S)

所以A=123我们最终会得到类似的东西(仅为“可读性”添加空格):

([2-9][0-9]{2}) | (1(([3-9][0-9]{1}) | (2(([4-9]) | 3))) )
于 2013-08-22T07:48:24.130 回答
2

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

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'));

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

于 2013-08-22T08:52:47.927 回答