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