user1614240
user1614240

Reputation: 107

Randing a string

$str = '[Hi|Hello|Aloha] [Kate|Ann|Polly]';

I need a function that will print me a random variation of the str. For example:

Hi Ann
Hello Polly
....
....

Anny ideas?

Upvotes: 0

Views: 146

Answers (4)

Thor
Thor

Reputation: 47099

I would use lists and list packages to do this, shuffle and pairwise come to mind, e.g.:

use 5.010;
use List::Util qw /shuffle/;
use List::MoreUtils qw/pairwise/;

$, = " ";

@greetings = shuffle qw(Hi Hello Aloha);
@names     = shuffle qw(Kate Ann Polly);

pairwise { say $a, $b } @greetings, @names;

Example output:

Hello Polly
Aloha Ann
Hi Kate

If you're stuck with the string format, you can convert it into lists with something like this:

$str = '[Hi|Hello|Aloha] [Kate|Ann|Polly]';
($greetings, $names) = $str =~ /\[([^]]+)\] +\[([^]]+)\]/;

@greetings = shuffle split /\|/, $greetings;
@names     = shuffle split /\|/, $names;

Upvotes: 1

ikegami
ikegami

Reputation: 385799

$str = '[Hi|Hello|Aloha] [Kate|Ann|Polly]';

$str =~ s{
    \[ ( [^\]]* ) \]
}{
    my @choices = split /\|/, $1;
    $choices[rand(@choices)]
}xeg;

say $str;

Upvotes: 4

amon
amon

Reputation: 57600

Combining two random elements from two arrays is rather trivial, and answered by @OleksandrBondarenko. The more interesting question is how to get a data structure from that string.

Possibility 1

Change your input format. You need two lists/arrays, not a string. If you can change your API or interface, doing that might be easier than using this string representation

Possibility 2

Create Perl code from that string and eval it. While this is easy, this is a severe security problem, so this should only be applied for one-time problems where the input is well known and trusted:

my $str = '[Hi|Hello|Aloha] [Kate|Ann|Polly]';
$str =~ s/ /,/g;            # '[Hi|Hello|Aloha],[Kate|Ann|Polly]'
$str =~ s/\|/","/g;         # '[Hi","Hello","Aloha],[Kate","Ann","Polly]'
$str =~ s/\[/["/g;          # '["Hi","Hello","Aloha],["Kate","Ann","Polly]'
$str =~ s/\]/"]/g;          # '["Hi","Hello","Aloha"],["Kate","Ann","Polly"]'
my @arrayrefs = eval $str;  # (["Hi","Hello","Aloha"],["Kate","Ann","Polly"])
my @greetings = @{shift @arrayrefs};
my @names     = @{shift @arrayrefs};

Do not do this in production code, as the string could contain any arbitrary code, possibly resulting in severe damage to your computer, files or security.

Possibility 3

Process and parse the data correctly. While this is sometimes difficult, it is the safest solution.

my $str = '[Hi|Hello|Aloha] [Kate|Ann|Polly]';
my @strings = split /(?<=\])\s+(?=\[)/, $str;
# for each $string in @strings:
$string =~ s/^\[//;  # 
$string =~ s/\]$//;  # or: $string = substr $str, 1, length $str -2;
my @parts = split /\|/, $string

The first @parts is the array of greetings, the second an array of names. This solution requires some further code I omitted.

The look-arounds in the first split regex are not really neccessary, but better than making assumptions about the data format.

Upvotes: 0

Oleksandr Bondarenko
Oleksandr Bondarenko

Reputation: 2018

Just generate two random numbers from the set {0,1,2} and build your greeting respectively. For example: if the generated numbers are 1 and 2, then you output 'Hello Polly'. If 2 and 0, then 'Aloha Kate'.

Upvotes: 2

Related Questions