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

I know there are good non-regex ways to do this

So this is just a challenge for the perversely curious.

($random_char) = "string" =~ /your_magic_here/s;

update: I was a bit hasty...

"string" =~ /(?=(?>^.*(?{$n=int rand$+[0]})))(??{".{$n}"})(.)/s

Replies are listed 'Best First'.
Re: Pick a random string char with a regex
by davido (Cardinal) on May 29, 2004 at 05:31 UTC
    This method uses only a single special (??{...}) expression within the RE, but unfortunately it requires that you know the named variable name of the string being passed to it. (See Update1)

    my $string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; my ($random) = $string =~ m/(??{'.'x rand length $string })(.)/s; print $random, "\n";

    ------------
    UPDATE1: And here it is without the dependancy on knowing the name of the scalar holding the string (Thanks perlre).

    my $string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; my( $random ) = $string =~ m/^(??{ '.' x rand length $_ })(.)/s; print "$random\n";

    I knew there had to be a way. ;)

    ------------
    UPDATE2: And here it is with a quantifier instead of a huge string of '.' metacharacters. The code is longer, but it's more friendly to real long target strings.

    my $string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; my ($random) = $string =~ m/^ (??{'.{' . int(rand length $_) . '}' }) (.) /sx; print "$random\n";

    Enjoy!


    Dave

Re: Pick a random string char with a regex
by Limbic~Region (Chancellor) on May 29, 2004 at 14:45 UTC
    bsb,
    This requires the string to be stored in the lexical $string, but you were looking for something perverse:
    #!/usr/bin/perl use strict; use warnings; package Random_Char; use PadWalker 'peek_my'; sub TIESCALAR { bless {}, $_[0] } sub STORE { return 1 } sub FETCH {my @c=keys%{{map{$_=>undef}split//,${peek_my(1)->{'$string' +}}}};return $c[rand @c];} package main; tie my $rand_char, "Random_Char"; my $string = 'One bright day in the middle of the night'; my ($char) = $string =~ /($rand_char)/; print "$char\n";
    Cheers - L~R

    Update:
    Here is another that is a bit more fragile that doesn't use modules.
    It works on the form ($char) =~ "some string" =~ /($rand_char)/;

    #!/usr/bin/perl use strict; use warnings; package Random_Char; sub TIESCALAR { bless {}, $_[0] } sub STORE { return 1 } sub FETCH {open(I,$0);my $l;while(<I>){$l=$_ and last if$.==(caller)[2 +]} $l =~ s/^.*=\s*(["'])(.*)\1\s*=~.*$/$2/;my @c=keys%{{ map{$_=>undef}split//,$l}};return $c[rand @c]; } package main; tie my $rand_char, "Random_Char"; my ($char) = 'One bright day in the middle of the night' =~ /($rand_ch +ar)/; print "$char\n";