[PERL] Mit Regex kompletten String durchsuchen und ersetzen

D

dummschnigger

Grünschnabel
Hallo alle zusammen,

ich habe ein Problem mit Regex in einem Perlscript. Ich möchte eine Templatedatei einlesen, bestimmte Werte ersetzen und die Daten danach in eine neue Datei schreiben. Einlesen und Ausgabe funzt. Ich lese die Datei komplett in einen String ein und bearbeite diesen dann mit einem regulären Ausdruck. In einer Steuerdatei stehen die ganzen Werte sowie die Ersetzungen drin.

Code:
host|ip
test1|192.168.1.1
test2|192.168.1.2
Folgende Variablen habe ich:
Code:
$tpl            -> die Templatedatei
@replace_titles -> Die Werte die gesucht werden sollen
@tmp_cfg        -> Die Werte die dann eingefügt werden sollen
Script:
Code:
  foreach my $line (@tmp_cfg) {
    my $tmp_tpl = $tpl;
    chomp($line);
    my @replace = split(/\|/, $line);

    for(my $c = 0; $c <= $#replace; $c++) {
      my $regex = 's/\{\{' . $replace_titles[$c] . '\}\}/' . $replace[$c] . '/egimox';
      $tmp_tpl =~ $regex;
    }
    print $tmp_tpl;
  }
Das steht dann in den Variablen drin:
Code:
@replace_titles[0] = 'host'
@replace_titles[1] = 'ip'
...
@tmp_cfg[0] = 'test1|192.168.1.1'
@tmp_cfg[1] = 'test2|192.168.1.2'
...
@replace[0] = 'test1'
@replace[1] = '192.168.1.1'
Meine Templatedatei sieht so aus
Code:
Hostname {{host}}
IP-Add {{ip}}
Es soll jetzt nach allen Werten in @replace_titles gesucht werden, die sich in einer doppelt geschweiften Klammer befinden und ersetzt werden.

Wenn ich das Script laufen lasse, dann bekomme ich mit dem "print $tmp_tpl;" nur den Inhalt der Templatedatei angezeigt, ohne dass die Veränderungen vorgenommen werden.

Wo ist mein Fehler? Ich schätze mal, dass irgendwas mit dem Ausdruck nicht stimmt, wahrscheinlich mit den Parametern hintendran.

Ich wäre für jegliche Hilfe dankbar.

/edit:
Die Suchwörter können auch mehrfach vorkommen und dann sollten alle auch ersetzt werden, z.B.:
Code:
Hostname {{host}}
IP-Add {{ip}}
Irgendwas {{host}}

/edit2:
ich habe gerade mal folgendes getestet:
Code:
$tmp_tpl =~ s/{{hostname}}/test1/g;

Wenn ich das so ausführe, wird das einwandfrei ersetzt. Anscheinend hängt es damit zusammen, wie ich den Ausdruck aufbaue.

Wenn ich den Ausdruck so aufbaue:
Code:
my $regex = s/\{\{$replace_titles[$c]\}\}/$replace[$c]/g;
dann bringt er mir diese Fehlermeldung:
Code:
Use of uninitialized value in substitution (s///) at ./create_cfg.pl line 112.
Irgendjemand 'ne Idee wie ich meine Variablen da rein bekomme?
 
Zuletzt bearbeitet:
Hallo

Wenn im $tmp_tpl wirklich ein multilinestring steht, dann brauchst du die Option m. Wozu du x und e hier einfügst, ist nicht klar.
Ich sehe weder ausführbaren Code noch Kommentare in dem Replaceteil.

Außerdem würde ich statt 2 Array lieber ein hash verwenden.
Der Schlüssel sei der Suchtext und der Wert der Replace-Text.
Dadurch stellst du auch gleich sicher, dass die Größe gleich groß ist.
Da du offensichtlich use strict verwendest (wie es sein soll) , könnte dein Fehler an einem Fehlenden Index liegen. Sprich das Ersetzungsarray ist kleiner als das Sucharray.
Das beschriebene Suchhash sei hier hash.
Code:
foreach (keys  %hash) {
     $tmp_tpl= ~s/\{\{'$_'\}\}/' $hash{$_} '/gim';
      
    }
    print $tmp_tpl;

Ob es geht kann ich nicht testen, da das nur ein Fragment ist.
BTW wozu eigentlich die Punkte?
Gruß Wolfgang
 
Zuletzt bearbeitet:
Hallo Wolfgang, danke für deine Hilfe.

Ich hatte das Problem heute mittag auf der Arbeit und kurz vor Feierabend habe ich dann die Lösung gefunden. Da ich dann keine Zeit mehr hatte die Lösung zu posten werde ich das morgen nachholen.

Wozu du x und e hier einfügst, ist nicht klar.
Ich sehe weder ausführbaren Code noch Kommentare in dem Replaceteil.
Das hatte ich in einem Tutorial so gefunden. Da ich in Perl noch relativ frisch bin dachte ich mir, dass ich es mit den Optionen einfach mal ausprobiere und das war dann der letzte Stand, bevor ich es hier gepostet hatte.

BTW wozu eigentlich die Punkte?
Das soll nur bedeuten das es da noch weitergeht, ich es aber gekürzt habe ;)
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

So, hier meine "Lösung" für das Problem.

Code:
for(my $c = 0; $c <= $#replace; $c++) {
  $tmp_tpl =~ s/{{$replace_titles[$c]}}/${replace[$c]}/g
}

So funktioniert es einwandfrei. Irgendwie hatte ich Probleme die Variablen gescheit in den regulären Ausdruck zu packen. In $replace_titles sind die Wörter drin die gesucht werden sollen und in $replace sind die Ersetzungen drin.
 
Zuletzt bearbeitet:
Hallo
Schön, dass du es lösen konntest.
Allerdings hast du meine Frage nach den Punkten missverstanden.
Code:
s/\{\{'[b][color=red] .[/color][/b] $replace_titles[$c] [b][color=red] .[/color][/b] '\}\}/' [b][color=red] .[/color][/b] $replace[$c] [b][color=red] .[/color][/b] '/
Diese Punkte meinte ich.
Ein Punkt bedeutet nämlich im Suchteil ein beliebiges Zeichen
Im Ersetzen Teil in verbindung mit Option e eine Stringverknüpfung.

Die von mir vorgeschlagene Hashlösung ist allerdings IMHO übersichtlicher.
Aber viele Wege führen Nach Rom.

Gruß Wolfgang
EDIT:
Du solltest bei deiner Lösung jedoch vorher prüfen, ob die Arrayindexe auch existieren, bzw. beide Arrays wirklich gleich groß sind. Sonst könnte es zu einem unerwarteten Abbruch kommen.
 
Zuletzt bearbeitet:
Code:
s/\{\{'[b][color=red] .[/color][/b] $replace_titles[$c] [b][color=red] .[/color][/b] '\}\}/' [b][color=red] .[/color][/b] $replace[$c] [b][color=red] .[/color][/b] '/
Diese Punkte meinte ich.
Ein Punkt bedeutet nämlich im Suchteil ein beliebiges Zeichen
Im Ersetzen Teil in verbindung mit Option e eine Stringverknüpfung.
Ah ok, dann hatte ich dich missverstanden ;) Ich dachte eigentlich, dass ich damit die einzelnen Teile zusammensetzen kann. Quasi wie eine Stringverkettung.

Die von mir vorgeschlagene Hashlösung ist allerdings IMHO übersichtlicher.
Aber viele Wege führen Nach Rom.
Das werde ich mir nochmal zu Gemüte führen. Das Problem war, dass ich das Script heute morgen gebraucht habe und da musste es einfach nur funktionieren.

Du solltest bei deiner Lösung jedoch vorher prüfen, ob die Arrayindexe auch existieren, bzw. beide Arrays wirklich gleich groß sind. Sonst könnte es zu einem unerwarteten Abbruch kommen.
s.o., danke für den Hinweis, das werde ich noch einbauen.
 
Ah ok, dann hatte ich dich missverstanden ;) Ich dachte eigentlich, dass ich damit die einzelnen Teile zusammensetzen kann. Quasi wie eine Stringverkettung.
Regexe in Perl sind schon von Natur aus in den Double-Quotes, d.h. darin enthaltene Variablen und Sonderzeichen werden geparst (dies ist der Unterschied zu den Single-Quotes, bei denen Sonderzeichen und Variablennamen praktisch wörtlich genommen werden).
 

Ähnliche Themen

Samba 4 Gast Zugang unter Ubuntu funktioniert nicht

NagiosGrapher 1.7.1 funktioniert nicht

Windows clients können nicht mehr auf lange laufendes System zugreifen

dovecot und postfix Konfiguration Problem

CentOS 6.3 RADIUS - Keine Verbindung möglich

Zurück
Oben