I am looking for something like this: How to generate a regular expression at runtime to match a numeric range but written in php.
            Asked
            
        
        
            Active
            
        
            Viewed 806 times
        
    1
            
            
        - 
                    Basic Java and PHP syntax are not THAT dissimilar, and regex syntax is pretty standardized too. WHy not try translating the regex in the other answer yourself? – Marc B Jun 28 '11 at 01:08
- 
                    How would I translate this statement: String.format(n==m ? n==1 ? "":"{%d}":"{%d,%d}", n, m) – Ivan Jun 28 '11 at 01:15
2 Answers
3
            
            
        Answering your question here, since comments are horrible for code blocks. I wouldn't translate a statement like that directly, as it's nearly unreadable. It's far easier to pick apart like this:
if ($n == $m) { // max/min ranges are the same, so just look for that number of characters
    $format = "\{$n\}";   // {n}
} elseif ($n == 1) { // min range is 1, so use the max
    $format = "\{1,$m\}";  // {1,m}
} else { // arbitary n->m range
    $format = "\{$n,$m\}";  // {n,m}
}
It CAN be done in PHP as a ternary, it's just as illegible/impossible to debug, though:
$format = ($n == $m) ? "\{$n\}" : (($n == 1) ? "\{1,$m\}" : "\{$n,$m\}");
 
    
    
        Marc B
        
- 356,200
- 43
- 426
- 500
0
            
            
        I think this should work:
class NumericRangeRegexGenerator {
private function baseRange($num,$up, $leading1) {
    $c = $num[0];
    $low  = $up ? $c : ($leading1 ? '1' : '0');
    $high = $up ? '9': $c;
    if (strlen($num) == 1)
        return $this->charClass($low, $high);
    $re = $c . "(" . $this->baseRange(substr($num,1), $up, false) . ")";
    if ($up) $low++; else $high--;
    if ($low <= $high)
        $re .= "|" . $this->charClass($low, $high) . $this->nDigits(strlen($num) - 1);
    return $re;
}
private function charClass($b, $e) {
    //String.format(b==e ? "%c" : e-b>1 ? "[%c-%c]" : "[%c%c]", b, e); (in java)
    if ($b == $e) {
        $format = $b; 
    } elseif ($e-$b>1) {
        $format = '['.$b.'-'.$e.']';
    } else {
        $format = '['.$b.$e.']';
    }
    return $format;
}
private function nDigits($n, $m=null) {
    //String.format(n==m ? n==1 ? "":"{%d}":"{%d,%d}", n, m) (in java)
            if($m===null){
                nDigits($n, $n);
            }
    if ($n == $m) { // max/min ranges are the same, so just look for that number of characters
        $format = "\{$n\}";   // {n}
    } elseif ($n == 1) { // min range is 1, so use the max
        $format = "\{1,$m\}";  // {1,m}
    } else { // arbitary n->m range
        $format = "\{$n,$m\}";  // {n,m}
    }
    return "[0-9]" . $format;
}
private function eqLengths($from, $to) {
    $fc = $from[0];
            $tc = $to[0];
    if (strlen($from) == 1 && strlen($to) == 1)
        return $this->charClass($fc, $tc);
    if ($fc == $tc)
        return $fc . "(".$this->rangeRegex(substr($from,1), substr($to,1)).")";
    $re = $fc . "(" . $this->baseRange(substr($from,1), true, false) . ")|"
              . $tc . "(" . $this->baseRange(substr($to,1),  false, false) . ")";
    if (++$fc <= --$tc)
        $re .= "|" . $this->charClass($fc, $tc) . $this->nDigits(strlen($from) - 1);
    return $re;
}    
private function nonEqLengths($from, $to) {
    $re = $this->baseRange($from,true,false) . "|" . $this->baseRange($to,false,true);
    if (strlen($to) - strlen($from) > 1)
        $re .= "|[1-9]" . $this->nDigits(strlen($from), strlen($to) - 2);
    return $re;
}
public function rangeRegex($n, $m) {
    return strlen($n) == strlen($m) ? $this->eqLengths($n, $m) : $this->nonEqLengths($n, $m);
}
}
 
    
    
        Ivan
        
- 46
- 5
- 
                    The code runs, but it's not giving me the desired results. For $regexer->rangeRegex(123, 321); I get (2([31])) , which is not correct. – Ivan Jun 28 '11 at 15:30
