Regex 101 Exercise I3 – Expand ranges in a string


I3 – Expand ranges in a string


Given a string like:


1,2,4,6-9,12,15-17,20


expand the ranges, so the final string is:


1,2,4,6,7,8,9,12,15,16,17,20


 

Comments (16)

  1. Maurits says:

    Stupid question time… are negative numbers disallowed? It’s much more complicated to have to watch out for things like

    -8–6,-5,-3-2,4-7

  2. dp says:

    But… why? That defeats the purpose of having the shorthand capabilities.

  3. ericgu says:

    Maurits,

    My intention is that they are all positive integers, but if you want to make it more complex, be my guest.

    dp,

    Like all the other exercises up ’til this one have had rational justifications?

    If you must have one, consider that you want to allow the user to specify a shorthand but the software you’re passing it doesn’t support one.

  4. Maurits says:

    Well, here’s two Perl solutions:

    http://www.geocities.com/mvaneerde/range-regex.pl.txt

    Don’t see how to do it easily in a .NET regex…

    A specific justification does come to mind. If you’re building a SQL string, this is valid..

    SELECT * FROM ThingsToDo WHERE ID IN (1,2,4,6,7,8,9,12,15,16,17,20)

    but this is not:

    SELECT * FROM ThingsToDo WHERE ID IN (1,2,4,6-9,12,15-17,20)

  5. Maurits says:

    (does some research)

    OK, here’s the C# equivalent:

    http://www.geocities.com/mvaneerde/range-regex.cs.txt

  6. Haacked says:

    Well one obvious justification is in implementing page ranges. For example a function to print all pages in the range "1-5,7,9-10".

    I’ve implemented something like this via a custome Enumerator. Never thought to use a Regex, which sounds like a neat way to go about it.

  7. Maurits says:

    This would be a handy place to use the "anonymous functions" feature of .Net 2.0 …

    new MatchEvaluator( /* anonymous function here… */ )

  8. Greg says:

    In Python:

    [i for j in [range(int(s.split(‘-‘)[0]), int(s.split(‘-‘)[-1:][0])+1) for s in ‘1,2,4, 6-9,12,15-17,20’.split(‘,’)] for i in j]

  9. Maurits says:

    Here’s a one-line Perl script that does it…

    Windows version:

    perl -e "$_ = shift; s/-/../g; print eval ‘join q(,), (‘ . $_ . ‘)’" 1,2,4,6-9,12,15-17,20

    Unix version:

    perl -e ‘$_ = shift; s/-/../g; print eval "join q(,), (" . $_ . ")"’ 1,2,4,6-9,12,15-17,20

    Challenge: find a shorter program (any language) that also works!

  10. Maurits says:

    Windows:

    perl -e "$_ = shift; s/-/../g; $, = ‘,’; print eval" 1,2,4,6-9,12,15-17,20

    Unix:

    perl -e ‘$_ = shift; s/-/../g; $, = ","; print eval’ 1,2,4,6-9,12,15-17,20

  11. Maurits says:

    Down to 63 characters, 21 of which are the data:

    Windows:

    echo 1,2,4,6-9,12,15-17,20|perl -ne"s/-/../g;$,=’,’;print eval"

    Unix:

    echo 1,2,4,6-9,12,15-17,20|perl -ne’s/-/../g;$,=",";print eval’

  12. droid says:

    As Maurits suggested earlier, seems the best way in .NET would be the MatchEvaluator. I couldn’t come up with a portable one-liner since it looks as if the perl (?{ code }) thing doesn’t seems to work.

    This doesn’t handle negative,decreasing and other cases..

    string pattern = @"([0-9]+)-([0-9]+)";

    Regex regex = new Regex(pattern, RegexOptions.IgnorePatternWhitespace);

    string result = regex.Replace(@"1,2,4,6-9,12,15-17,20",

    (MatchEvaluator)delegate(Match tempmatch) {

    int s = int.Parse(tempmatch.Groups[1].Value);

    int e = int.Parse(tempmatch.Groups[2].Value);

    int i; StringBuilder sb = new StringBuilder();

    for (i = s; i < e; i++) { sb.Append(i); sb.Append(","); }

    return sb.Append(i).ToString(); }

    );

  13. droid says:

    ups.. The (MatchEvaluator) cast is not needed.