If I had a text file with the following:
Today (is|will be) a (great|good|nice) day.
Is there a simple way I can generate a random output like:
Today is a great day. Today will be a nice day.
Using Perl or UNIX utils?
If I had a text file with the following:
Today (is|will be) a (great|good|nice) day.
Is there a simple way I can generate a random output like:
Today is a great day. Today will be a nice day.
Using Perl or UNIX utils?
Code:
#!/usr/bin/perl
use strict;
use warnings;
my $template = 'Today (is|will be) a (great|good|nice) day.';
for (1..10) {
print pick_one($template), "\n";
}
exit;
sub pick_one {
my ($template) = @_;
$template =~ s{\(([^)]+)\)}{get_random_part($1)}ge;
return $template;
}
sub get_random_part {
my $string = shift;
my @parts = split /\|/, $string;
return $parts[rand @parts];
}
Logic:
my $template = ...
)for ...
)pick_one
to do the work"(...)"
substrings, and replace them with random part ($template =~ s...
)Getting random part is simple:
my $string = shift
)|
character (my @parts = ...
)return $parts[...
)That's basically all. Instead of using function you could put the same logic in s{}{}
, but it would be a bit less readable:
$template =~ s{\( ( [^)]+ ) \)}
{ my @parts = split /\|/, $1;
$parts[rand @parts];
}gex;
Smells like a recursive algorithm
Edit: misread and thought you wanted all possibilities
#!/usr/bin/python
import re, random
def expand(line, all):
result = re.search('\([^\)]+\)', line)
if result:
variants = result.group(0)[1:-1].split("|")
for v in variants:
expand(line[:result.start()] + v + line[result.end():], all)
else:
all.append(line)
return all
line = "Today (is|will be) a (great|good|nice) day."
all = expand(line, [])
# choose a random possibility at the end:
print random.choice(all)
A similar construct that produces a single random line:
def expand_rnd(line):
result = re.search('\([^\)]+\)', line)
if result:
variants = result.group(0)[1:-1].split("|")
choice = random.choice(variants)
return expand_rnd(
line[:result.start()] + choice + line[result.end():])
else:
return line
Will fail however on nested constructs
Closures are fun:
#!/usr/bin/perl
use strict;
use warnings;
my @gens = map { make_generator($_, qr~\|~) } (
'Today (is|will be) a (great|good|nice) day.',
'The returns this (month|quarter|year) will be (1%|5%|10%).',
'Must escape %% signs here, but not here (%|@).'
);
for ( 1 .. 5 ) {
print $_->(), "\n" for @gens;
}
sub make_generator {
my ($tmpl, $sep) = @_;
my @lists;
while ( $tmpl =~ s{\( ( [^)]+ ) \)}{%s}x ) {
push @lists, [ split $sep, $1 ];
}
return sub {
sprintf $tmpl, map { $_->[rand @$_] } @lists
};
}
Output:
C:\Temp> h Today will be a great day. The returns this month will be 1%. Must escape % signs here, but not here @. Today will be a great day. The returns this year will be 5%. Must escape % signs here, but not here @. Today will be a good day. The returns this quarter will be 10%. Must escape % signs here, but not here %. Today is a good day. The returns this month will be 1%. Must escape % signs here, but not here %. Today is a great day. The returns this quarter will be 5%. Must escape % signs here, but not here @.
Sounds like you may be looking for Regexp::Genex. From the module's synopsis:
#!/usr/bin/perl -l
use Regexp::Genex qw(:all);
$regex = shift || "a(b|c)d{2,4}?";
print "Trying: $regex";
print for strings($regex);
# abdd
# abddd
# abdddd
# acdd
# acddd
# acdddd