Got more questions? Find advice on: ASP | SQL | XML | Windows
in Search
Welcome to RegexAdvice Sign in | Join | Help

Justin's Regex Blog

Thinking in Regex

Thanks to Darren, I had to examine the process of neg-pos neg-neg ranges in addition to what I was already doing.

Negative ranges are actually quite easy to implement.  There are a couple of options:

    1. Parm1 +, Parm2 +
    2. Parm1 -, Parm2 -
    3. Parm1 -, Parm2 0
    4. Parm1 0, Parm2 -
    5. Parm1 +, Parm2 0
    6. Parm1 0, Parm2 +

6 options isn't that bad.  We also have relative equality, but we'll get to that.  So we have some new scenarios.  The first is a parm1 being negative and parm2 being neg or 0.  This is basically a postive range with a negative symbol attached:

return "-" + BuildCaptureForRange(Math.Abs(range1), Math.Abs(range2));

Next we have parm1 still negative with the absolute value equal to parm2.  This is the cast of -500 through 500 and we want to special case it by making an optional negative symbol.

return "-?" + BuildCaptureForRange(0, range2);

The final special case is that we have a negative and postive value.  This is basically two ranges, one from 0 to Abs(parm1) and one from 0 to parm2.  We switch between the two cases using a conditional expression of (?(-)-(neg range)|(pos range)).

return "(?(-)-" + BuildCaptureForRange(0, Math.Abs(range1)) + "|" + BuildCaptureForRange(0, range2) + ")";

Note that I've minimized the number of special cases by pre-sorting parm1 and parm2 by value to make sure the lesser value is always in the first local.  I also have a special case (value) whenever range1 is equal to range2.  The overall code appears to be:

// quick return for simple ranges
if ( range1 == range2 ) {
    return "(" + range1 + ")";
}

// Swap the min/max values
if ( range1 > range2 ) {
    int temp = range2;
    range2 = range1;
    range1 = temp;
}

if ( range1 < 0 && range2 <= 0 ){
    return "-" + BuildCaptureForRange(Math.Abs(range1), Math.Abs(range2));
} else if ( range1 < 0 ) {
    if ( Math.Abs(range1) == range2 ) {
        return "-?" + BuildCaptureForRange(0, range2);
    } else {
        return "(?(-)-" + BuildCaptureForRange(0, Math.Abs(range1)) + "|" + BuildCaptureForRange(0, range2) + ")";
    }
}

Now that I've completed my Darren Task I can probably go to bed.  You can't mention something to me and not expect some code the next day (hour or maybe even minute).  For testing, I'm including a sample batch file for you to run over top of your own algorithms:

@echo off
BuildRangeGroups 5 255
BuildRangeGroups 222 228
BuildRangeGroups 699 700
BuildRangeGroups 699 701
BuildRangeGroups 699 710
BuildRangeGroups 698 710
BuildRangeGroups 7650 7710
BuildRangeGroups 50 7710
BuildRangeGroups 6998998 7000000
BuildRangeGroups 7000 7999
BuildRangeGroups 7555 7999
BuildRangeGroups 1000 11000
BuildRangeGroups 0 69989
BuildRangeGroups -500 0
BuildRangeGroups -500 500
BuildRangeGroups 0 -500
BuildRangeGroups 500 -500
BuildRangeGroups -50 7710
BuildRangeGroups -1000 69989
BuildRangeGroups 0 1000
BuildRangeGroups 0 255
BuildRangeGroups 0 5000
BuildRangeGroups 0 11000

Along with the required output so you can validate that your algorithm is complete.  If you only want to implement part of the algorithm, then that is fine.  Nothing requires that you implement the entire thing.  Just use the expressions below as reference.  Also, let me know if you think there is a range of specific note that might cause issues with a generator or even if some of my generated expressions below are inaccurate.

(25[0-5]|[5-9]|2[0-4]\d|1?\d\d)
(22[2-8])
(700|699|[7-6]\d\d)
(699|70[01]|[7-6]\d\d)
(710|699|70\d|[7-6]\d\d)
(710|69[89]|70\d|[7-6]\d\d)
(7710|770\d|76[5-9]\d|7[7-6]\d\d)
(7710|770\d|[5-9]\d|7[0-6]\d\d|[1-6]?\d\d\d)
(7000000|699899[89]|6999\d\d\d|[7-6]\d\d\d\d\d\d)
(7\d\d\d)
(755[5-9]|75[6-9]\d|7[6-9]\d\d)
(11000|10\d\d\d|[1-9]\d\d\d|\d\d\d\d)
(699[0-8]\d|69[0-8]\d\d|6[0-8]\d\d\d|[1-5]?\d?\d?\d?\d)
-(500|[1-4]?\d?\d)
-?(500|[1-4]?\d?\d)
-(500|[1-4]?\d?\d)
-?(500|[1-4]?\d?\d)
(?(-)-(50|[1-4]?\d)|(7710|770\d|7[0-6]\d\d|[1-6]?\d?\d?\d))
(?(-)-(1000|\d?\d?\d)|(699[0-8]\d|69[0-8]\d\d|6[0-8]\d\d\d|[1-5]?\d?\d?\d?\d))
(1000|\d?\d?\d)
(25[0-5]|2[0-4]\d|1?\d?\d)
(5000|[1-4]?\d?\d?\d)
(11000|10\d\d\d|\d?\d?\d?\d)

Sponsor
Published Tuesday, May 25, 2004 2:46 AM by jrogers

Comments

 

jrogers said:

That's great Justin, now... if you'd just slow your output down enough that I can stop reading your stuff long enough to put a sample together I might still get to whip your sorry ass! ;-)

Just kidding mate... keep up the great work. I promise to have something available soon :-)
May 25, 2004 4:15 AM
Anonymous comments are disabled