[comp.lang.perl] Can this be done more slickly

victor@arnor.UUCP (Victor Miller) (03/16/91)

I wrote the function given below to transform a string with -'s in it
so that all alphabetics were lower case, except at the beginning of
the string or immediately after a dash, in which case it would be
upper case.  The follow works correctly, but I was wondering (in the
JAPH spirit), if there is a more clever (or concise) way of doing it.

sub normalize {
	local(@pieces) = split(/-/,$_[0]);
	local($i);
	foreach $i (0..$#pieces) {
	    $pieces[$i] =~ tr/A-Z/a-z/;
	    substr($pieces[$i],0,1) =~ tr/a-z/A-Z/;
	}
	join('-',@pieces);
    }



--
			Victor S. Miller
			Vnet and Bitnet:  VICTOR at WATSON
			Internet: victor@ibm.com
			IBM, TJ Watson Research Center

lwall@jpl-devvax.jpl.nasa.gov (Larry Wall) (03/16/91)

In article <VICTOR.91Mar15171726@irt.watson.ibm.com> victor@ibm.com writes:
: I wrote the function given below to transform a string with -'s in it
: so that all alphabetics were lower case, except at the beginning of
: the string or immediately after a dash, in which case it would be
: upper case.  The follow works correctly, but I was wondering (in the
: JAPH spirit), if there is a more clever (or concise) way of doing it.
: 
: sub normalize {
: 	local(@pieces) = split(/-/,$_[0]);
: 	local($i);
: 	foreach $i (0..$#pieces) {
: 	    $pieces[$i] =~ tr/A-Z/a-z/;
: 	    substr($pieces[$i],0,1) =~ tr/a-z/A-Z/;
: 	}
: 	join('-',@pieces);
:     }

Oh, there's probably several things we can do to improve it.  First,
you don't need to use an index:

    sub normalize {
	local(@pieces) = split(/-/,$_[0]);
	foreach $piece (@pieces) {
	    $piece =~ tr/A-Z/a-z/;
	    substr($piece,0,1) =~ tr/a-z/A-Z/;
	}
	join('-',@pieces);
    }

You could get a little more concise with a substitute instead of a split:

    sub normalize {
	local($_) = @_;
	local($tmp);
	tr/A-Z/a-z/;
	s#((^|-)[a-z])#($tmp = $2) =~ tr/A-Z/a-z/,$tmp#eg;
	$_;
    }

That's still a bit gross.  With 4.0, you'll be able to do it like this:

    sub normalize {
	local(@pieces) = split(/-/,$_[0]);
	foreach $piece (@pieces) {
	    $piece = "\u\L$piece";
	}
	join('-',@pieces);
    }

or

    sub normalize {
	local($_) = "\u\L$_[0]";
	s/-([a-z])/-\u$1/g;
	$_;
    }

or, for those who prefer one-liners,

    sub normalize { join('-', grep(s/(.*)/\u\L$1/, split(/-/, $_[0]))); }

Larry

tchrist@convex.COM (Tom Christiansen) (03/16/91)

From the keyboard of victor@ibm.com:
:I wrote the function given below to transform a string with -'s in it
:so that all alphabetics were lower case, except at the beginning of
:the string or immediately after a dash, in which case it would be
:upper case.  The follow works correctly, but I was wondering (in the
:JAPH spirit), if there is a more clever (or concise) way of doing it.

:sub normalize {
:	local(@pieces) = split(/-/,$_[0]);
:	local($i);
:	foreach $i (0..$#pieces) {
:	    $pieces[$i] =~ tr/A-Z/a-z/;
:	    substr($pieces[$i],0,1) =~ tr/a-z/A-Z/;
:	}
:	join('-',@pieces);
:    }

Before 4.0, you have to use this:

    sub normalize { 
       local($_) = @_;
       tr/A-Z/a-z/;
       substr($_,$[,1) =~ tr/a-z/A-Z/;
       s/(-[a-z])/$x = tr#a-z#A-Z#, $x/ge;
       $_;
    }


But at 4.0beta or above, this works, and runs in just 40% the time of 
my previous example:

    sub normalize { 
       local($_) = @_;
       tr/A-Z/a-z/;
       substr($_,$[,1) =~ tr/a-z/A-Z/;
       s/-([a-z])/-\u$1/g;
       $_;
    }

The first two tr's could have been done with \L and \u escapes, but 
the tr's run a good faster that they do in those cases.

--tom