in reply to Re: How do I reverse the order of the first and last word of a string?
in thread How do I reverse the order of the first and last word of a string?

I quite like this solution to the problem as an interesting technique for impressing teachers:

++ for the funny reply, just as much as Anno's one. However...

my $str = "This is my program"; my @words = split ' ', $str;

[Still joking] This solution degrades whitespace, which his teacher may not want, and would earn him a bad mark. I'm astonished that no one took this into account yet. However the solution is easy:

my @chunks = split /(\s+)/, $str;

I changed @words to @chunks because they're not "words" any more. Of course later you may want to join on '' rather than on ' '.

But... Oh no! If there's leading or trailing whitespace, then this solution will be broken. And I don't want it to earn him a bad mark. Thus the first thing to do is to get rid of the empty leading field:

shift @chunks if $chunks[0] eq ''; # and then my $s = $chunks[0] =~ /\s/ ? 1 : 0; my $e = $chunks[-1] =~ /\s/ ? -2 : -1;

Later, you'd use $s and $e instead of 0 and -1. Of course, since the code defining $s and $e is very similar, it may be factored away as to define both of them at the same time by means of map:

my ($s,$e)=map $_ + ($chunks[$_] =~ /\s/ ? ($_ >=0 ? 1 : -1 ) : 0) => 0, -1;

We still want to earn him some extra marks, don't we?

map {s/[^a-z ]//gi} @words;

[On a more serious basis] I know that the tone of your answer is being sarcastic, but it also spawned some interest because of the notorious XOR technique, and up until now it has been a funny way to do something that one would better do differently. But it was also fundamentally correct, i.e. it exposed no Perl bad programming habit, while the OP is clearly a newbie and learning. So now what you show him is a use of map in void context for its side effects only, with a s used as a tr. If really wanting to use map, (and not having yet a .subst()) that should be

@words = map { (my $s=$_) =~ s/[^a-z ]//gi; $s } @words;

Moreover, the only spurious charachter will be a "\0" so with a

y/\0//d for @chunks; # or @chunks[$e,$s];

we would lose some irony but do a better instructive job.

Back to the joke! What could we do to earn the OP some more marks? Well, there are too many "chunks" around, and we may use the same trick as Anno's to factor them away. And as someone suggested, use interpolation in a double quoted string. The teacher will certainly be happy:

for ([split /(\s+)/, $str]) { shift @$_ if $_->[0] eq ''; my ($s,$e)= do { my @c=@$_; map $_ + ($c[$_] =~ /\s/ ? ($_ >=0 ? 1 : -1 ) : 0) => 0, -1; }; $_->[$s] ^= $_->[$e]; $_->[$e] ^= $_->[$s]; $_->[$s] ^= $_->[$e]; y/\0//d for @$_; local $"=''; print "@$_"; }

Replies are listed 'Best First'.
Re: How do I reverse the order of the first and last word of a string?
by jonadab (Parson) on Mar 11, 2007 at 11:35 UTC
    my @chunks = split /(\s+)/, $str;

    I prefer not to throw anything away in such cases:

    my @chunk = split /(?<=\b)(?=\w)/, $str;

    Of course this complicates the code for reversing a word, as you have to keep the trailing whitespace at the end (which can be accomplished with sort if you're careful), but it also means that if the original has two spaces after a word, your final result will too!

    -- 
    We're working on a six-year set of freely redistributable Vacation Bible School materials.