uvnew has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have strings of different lengths with zero, one or more '*' hiding somewhere. I'm looking for an elegant way of getting the location of the first '*'. So for example, if I have this string: sakg*ougaeou*lsjahg then I will get the number 5 (or 4, doesn't matter). If there are no '*' then I just want the length of the string. Thanks in advance!

Replies are listed 'Best First'.
Re: Finding location
by Corion (Patriarch) on Mar 09, 2007 at 10:13 UTC

    See the index function - you'll have to handle the case of the substring not being found special but that shouldn't be much of a problem.

      index can be persuaded to return the string length on non_match:
      my $pos = index( "$str*", '*');
      Anno
Re: Finding location
by GrandFather (Saint) on Mar 09, 2007 at 10:16 UTC

    The first part is easy, use index. The length requirement means an additional test:

    my $pos = index $str, '*'; $pos = length $str if $pos < 0;

    DWIM is Perl's answer to Gödel
Re: Finding location
by davidrw (Prior) on Mar 09, 2007 at 15:12 UTC
    if 1-based answer, then (basically same as the above replies):
    my $loc = (index($s, '*')+1) || length($s);
    Just note that the strings '12*' and '123' will both yield 3 ...
    If you want the latter to return '4' instead, could do:
    my $loc = (index($s, '*')+1) || (length($s)+1);
    Or, w/zero-base (so '12*'=>2 and '123'=>3), can do:
    my $loc = ( (index($s, '*')+1) || (length($s)+1) ) - 1;
    maybe not the clearest--but one-line, if that's your definition of "elegant" :)
    "better" is perhaps more like (or making a sub):
    my $loc = do { my $i = index $s, '*'; $i < 0 ? length($s) : $i };
Re: Finding location
by Util (Priest) on Mar 10, 2007 at 05:19 UTC

    You are certain to use $pos later in your code; *how* do you use it? Consider looking past the elegance of a single line, toward the elegant interplay within the *paragraph* of code. Your need for a separate $pos variable might even vanish, leaving a Zen-like elegance by its absence.

    Some late-night thoughts:

    # One-liners; different than the other Monks, but not better. my $pos = length( (split /\*/, $str)[0] ); my $pos = ( $str =~ m{ \A ( [^*]+ ) }x ) ? length($1) : 0;

    # Get all the positions my @positions; push @positions, pos($str)-1 while $str =~ m{\*}g; # Yields ( 4, 12 );

    # Get all the asterisk-separated pieces my @pieces = split "\*", $str; my $pos = length $pieces[0];

    # Just get the first piece my ( $first_piece ) = ( $str =~ m{ \A ( [^*]* ) }x ); my $pos = length $first_piece;