2009-08-14 5 views
0

verwenden, wenn ich mit dem im Anschluss an eine Textdatei hatte:Parsing-Dateien, die Synonyme

 
    Today (is|will be) a (great|good|nice) day. 

Gibt es eine einfache Weise, die ich eine zufällige Ausgabe wie erzeugen kann:

 
    Today is a great day. 
    Today will be a nice day. 

Mit Perl oder UNIX-utils ?

Antwort

7

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:

  1. Vorlage der Ausgabe definieren (my $template = ...)
  2. Geben Sie Schleife Zufallsausgangs viele Male (for ...)
  3. Anruf pick_one drucken Mach die Arbeit
  4. Suche aller "(...)" Substrings, und ersetzen sie durch zufälligen Teil ($template =~ s...)
  5. Druck erzeugte Zeichenfolge

Ersten Zufall Teil einfach:

  1. erhalten extrahierte String (my $string = shift)
  2. es gespalten mit | Zeichen (my @parts = ...)
  3. Rückkehr zufälliger Teil (return $parts[...)

Das ist im Grunde alles.Statt Verwendung der Funktion könnten Sie die gleiche Logik in s{}{} setzen, aber es wäre ein bisschen weniger lesbar sein:

$template =~ s{\(([^)]+) \)} 
       { my @parts = split /\|/, $1; 
       $parts[rand @parts]; 
       }gex; 
+0

+1 Es scheint wie die gleiche Antwort geschrieben, ohne Ihre zu sehen. Ich werde meine löschen. Übrigens, keine Notwendigkeit für "skalar", da "rand" sein erstes Argument im skalaren Kontext auswertet. –

+1

Ich weiß darüber, aber ich ziehe es vor, es (Skalar) einzufügen, um sicherzustellen, dass es 100% lesbar und nicht mehrdeutig ist. –

+0

@depesz Verstanden. Ich bin das Gegenteil. –

3
  1. Verwenden Sie eine Regex, um alle Klammern (und den darin enthaltenen Text) zu vergleichen.
  2. Verwenden Sie eine Zeichenfolge aufgeteilt Operation (Pipe-Trennzeichen) auf den Text innerhalb der übereinstimmenden Klammern, um jede der Optionen zu erhalten.
  3. Wählen Sie eine nach dem Zufallsprinzip.
  4. Geben Sie es als Ersatz für diese Erfassung zurück.
2

Riecht wie ein rekursiven Algorithmus

Edit: misread und haben Sie alle Möglichkeiten, wollte

#!/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) 

ein ähnliches Konstrukt, das eine einzelne Zeile erzeugt Zufalls:

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 

Wird jedoch auf verschachtelte Konstrukte

+0

Komm schon Leute, nur weil es nicht perl ist? Es ist der Algorithmus, der interessant ist –

+0

Ich habe nicht downvote, aber Sie haben Recht, das OP fragte nach irgendeiner * nix Lösung, also gebe ich Ihnen meine Stimme. –

+0

+1 für die Arbeit Python-Lösung. Ich mache die meiste Zeit meine Arbeit in Python, das ist sehr hilfreich für mich. :) – Lin

8

Verschlüsse sind Spaß fehlschlagen:

#!/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 
    }; 
} 

Ausgang:

 
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 @. 
+0

Dies ist eine nette Antwort, dachte ich glaube nicht, dass jemand, der nicht mjd Buch gelesen hat es versteht ... –

+1

* Higher Order Perl * (die jetzt kostenlos verfügbar ist: http: //hop.perl. plover.com/ - Ich habe dafür bezahlt und es war jeden Cent wert) ist das Werk eines Genies. Ich habe nur versucht, meine erste Antwort zu verbessern ;-) –

+0

+1 Ich kann dem nicht folgen, aber es ist großartig, um mir zu helfen, Perl zu lernen. Vielen Dank! – Lin

6

Klingt wie Sie für Regexp::Genex suchen können. Aus der Zusammenfassung des Moduls:

#!/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 
+0

Nun, das funktioniert nicht so gut. "(ist | wird sein)" funktioniert, aber "Heute (ist | wird sein)" scheitert sofort. Sie müssen also die "()" Teile identifizieren und verarbeiten, was die Verwendung dieses Moduls ziemlich sinnlos macht. –

Verwandte Themen