Range regexps II

This post described the littlest little language I’ve ever implemented, which would expand ranges like ‘A-Z’ or ‘0-9′ in a string. Following some suggestions by BKB in the comments, here’s a bunch of stylistic alternatives.

My first one was kind of over-cautious. The range-expansion logic is separated out into its own function, which handles dumb stuff like invalid ranges, and also documents itself. Although ‘expand_range’ would be a better name for that.

    s/(.)-(.)/expand_pair($1, $2)/eg

BKB got it into one line. I wouldn’t do it like this, because on returning to this code, I’d have to spend too much time remembering what it was supposed to be doing:

    s/(.)-(.)/join('', map { chr($_) } ord($1)..ord($2))/eg

BKB’s first version was this, which he corrected:

    s/(.)-(.)/join('', $1..$2)/eg

I tried it, just to see what would happen, and found that the ‘..’ operator will not just return (1, 2, 3, 4, 5) from 1..5: it will also return (‘a’, ‘b’, ‘c’, ‘d’, ‘e’) from ‘a’..’b’ or (‘A’, ‘B’, ‘C’, ‘D’, ‘E’) from ‘A’..’Z’ In other words, it works for most useful cases.

In one way, I like this version the most: it’s a highly readable one-liner which works. In another way, I like it the least, because if you think about it for a little bit, it seems like it might be broken.

I then tried this, just to see what would happen:

    s/(.)-(.)/$1..$2/eg;

It turns every range into ‘1E0′, but I haven’t yet figured out why. Sometimes you just want to see how much tomfoolery Perl will put up with.

One Response to “Range regexps II”

  1. BKB Says:

    That doesn’t turn every range into 1E0. 0-3 gets turned into an undefined value. The 1E0 looks like a bug in Perl. Note that $1..$2 is a list and it’s being evaluated in scalar context, so we’d expect to get the number of elements in the list.

    By the way, perhaps you already know this, but an explanation of why the range works as it does can be found in

    http://perldoc.perl.org/perlop.html#Range-Operators


Leave a Reply