2012-05-16 7 views
6

Sagen wir, ich möchte in einem großen (300.000 Buchstaben) das Wort "Hunde" mit dem Abstand zwischen den Buchstaben genau 40.000 Buchstaben dazwischen finden. So tue ich:Perl: "Quantifier in {,} größer als 32766 in Regex"

$mystring =~ m/d.{40000}o.{40000}g.{40000}s/; 

Diese in anderen (langsamer) Sprachen ganz gut funktioniert, aber in Perl es wirft mich "Quantifizierer in {,} größer als 32766 in regex".

So:

  1. Können wir eine größere Zahl als Quantor verwenden irgendwie?
  2. Wenn nicht, gibt es einen anderen guten Weg, um zu finden, was ich will? Beachten Sie, dass "Hunde" nur ein Beispiel ist; Ich möchte dies für jedes Wort und jede Sprunggröße (und schnell) tun.

Antwort

9

Wenn Sie wirklich diese schnell tun müssen, ich auf einer benutzerdefinierten Suche basiert auf den Ideen von Boyer-Moore string search aussehen würde. Ein regulärer Ausdruck wird in eine endliche Zustandsmaschine geparst. Selbst eine clevere, kompakte Darstellung einer solchen FSM wird keine sehr effektive Art sein, eine Suche, wie Sie sie beschreiben, auszuführen.

Wenn Sie wirklich entlang der Linien fortfahren möchten, die Sie jetzt sind, können Sie einfach zwei Ausdrücke wie .{30000}.{10000} verketten, die in der Praxis mit .{40000} identisch sind.

+0

Nice work-around. Ich dachte darüber nach, etwas von Grund auf neu zu schreiben, aber es ist ein wenig übertrieben für mich, da die Suchanfragen, die ich in der Brute-Force-Regex-Methode durchführe, nur etwa zehn Minuten dauern werden. –

+0

@GadiA Ich wäre gespannt, ob "Lernen" die Leistung des Spiels verbessern würde. –

5

Ich denke, index könnte besser für diese Aufgabe geeignet sein. Etwas nach dem Vorbild der völlig ungetestet:

sub has_dogs { 
    my $str = shift; 
    my $start = 0 

    while (-1 < (my $pos = index $$str, 'd', $start)) { 
     no warnings 'uninitialized'; 
     if (('o' eq substr($$str, $pos + 40_000, 1)) and 
      ('g' eq substr($$str, $pos + 80_000, 1)) and 
      ('s' eq substr($$str, $pos + 120_000, 1))) { 
      return 1; 
     } 
    } 
    return; 
} 
5

40.000 = 2 * 20.000

/d(?:.{20000}){2}o(?:.{20000}){2}g(?:.{20000}){2}s/s 
+0

Es ist einfach, das Obige mechanisch zu machen, also erfüllt es Ihre Anfrage nach "jeder Größe". Zweitens möchten Sie wirklich "s" verwenden, da sonst/'./Means /' [^ \ n] '/ viele unnötige Überprüfungen erfordern würden. – ikegami