2017-01-11 3 views
0

Ich benutze Perl v5.10 auf CentOS 6.8Perl regex Maschine Namen von Hostnamen extrahieren

Mein Programm eine Liste der Hostnamen liest in Perl-Array @aVmList. Ich versuche, nur den Maschinennamen von jedem von ihnen zu extrahieren.

Einige der Hostnamen sind vollständig qualifiziert, andere nicht. Einige enthalten Bindestriche oder Unterstriche.

Ich habe keine Kontrolle über den Inhalt des Arrays.

Hier ist ein Beispiel für die Daten, mit denen ich arbeite.

my @aVmList = qw(
    vmserver1.domain.com 
    vmserver2 
    vm-server-three.otherdomain.com 
    server_four.domain.com 
    server5 
    server6 
    some-silly-vm-name 
    another_server.maybewithadomain.com 
); 

Ich möchte Name nur das Gerät von jedem Element extrahieren, mit dem folgenden enden.

vmserver1 
vmserver2 
vm-server-three 
server_four 
server5 
server6 
some-silly-vm-name 
another_server 

fand ich die Regex /(.*?)\./ die fast funktioniert, aber nur dann, wenn alle Namen sind vollständig qualifiziert.

foreach (@aVmList) { 

    $_ =~ /(.*?)\./; 

    my $sVmName = $1; 

    print $sVmName; 
} 

Ich dachte, ich für die Punkte ein Blick hinter die Verwendung benötigt. Ich kam mit der folgenden

$_ =~ /([A-Za-z0-9-_]+)(?!=\.)/; 

auf, die in der Regex Tester schien zu funktionieren, aber wenn ich meine Perl-Skript lief es abgestimmt noch die gesamte Zeichenfolge.

Ich mag nicht den Pfad, den ich mit dem obigen Regex-Muster gehe, weil ich jetzt nehme, dass die Host-Namen nur "Wort" -Zeichen oder einen Bindestrich enthalten.

Ich weiß, ich sollte nicht Sonderzeichen in Host-Namen berücksichtigen müssen, aber ich versuche, das Regex-Muster auf alles vor dem ersten Punkt in einem Domain-Namen suffix.something.com.

Ich fand auch Regular expression to extract hostname from fully qualified domain name , die sich anhörte wie, was ich wollte, aber keiner der Vorschläge von dort zu arbeiten schien.

Ich habe versucht:

$_ =~ (.+?)(?=\.) 

und

$_ =~ ^([^.]+)\..*$ 
+1

Teilen Sie Ihre Zeichenfolge auf Punkte und nehmen Sie den ersten Teil. –

+0

'[A-Za-z0-9 -_] +' wird normalerweise geschrieben '[\ w-]' – Borodin

Antwort

1

Die negierte Zeichenklasse[^...] jedes Zeichen außer den genannten Angaben. Dann

my ($name) = $_ =~ /([^.]+)/; 

Matches alle Zeichen bis zum ersten . und hält es an, so gibt es keinen Grund, um explizit den Punkt übereinstimmen (noch den Rest der Linie). Die Übereinstimmung wird erfasst und $name zugewiesen.


Wenn der Match-Operator im Kontext Liste verwendet wird es gibt die Liste aller Spiele

my @matches = $var =~ m/$pattern/g; 

Auch wenn es nur ein Spiel wir die Liste Kontext brauchen, ist so, dass Die Übereinstimmung wird zurückgegeben, also die Klammer in my ($name) = ..., um den Listenkontext auf den Match-Operator aufzuerlegen. Im obigen Beispiel geschieht dies durch Zuordnung zu einem Array. Sonst hätten wir den skalaren Kontext , in diesem Fall verhält sich der Match-Operator anders. Siehe hierzu in perlop und siehe perlretut.

Die m oben kann weggelassen werden und am häufigsten ist. Beachten Sie jedoch, dass dies nicht immer der Fall ist, zum Beispiel wenn verschiedene Delimeter verwendet werden. Ich schlage vor, eine gute Lektüre durch perlretut.

Der Standardeingabe- und Mustersuchbereich ($_) in Ihrer Schleife enthält das aktuell verarbeitete Element. Regex funktioniert standardmäßig mit $_, so dass $_ nicht angegeben werden muss. Siehe General Variables in perlvar, und sehen Sie sich einen regexbezogenen Kommentar in der perlop-Verknüpfung an. So können Sie tun

foreach (@vm_list) { 
    /([^.]+)/;   # OK but better assign directly from the match 
    my $host_name = $1; 
} 

Allerdings ist es klarer, direkt aus dem Spiel zuweisen, wie in der Antwort.

+0

Ich denke, Sie haben das OP hier unten gelassen. Dies ist ein sehr kleiner Teil ihrer Lösung und erklären Sie um Himmels willen, dass '$ _' der Standardoperand ist. – Borodin

+1

@Borodin Es schien mir nicht, dass dies ein Problem war, sondern dass sie zuerst das Idiom '([^ X] +) 'sehen mussten. Aber bei einer sorgfältigeren Lektüre ... haben Sie Recht mit Erklärungen, hinzugefügt. – zdim

1

Ich denke, du machst das komplizierter, als es sein muss. Split auf Perioden und verwenden Sie den ersten Teil:

use strict; 
use warnings; 
use 5.012; 

while (<DATA>) { 
    chomp; 
    say ((split(/\./))[0]); 
} 

__DATA__ 
vmserver1.domain.com 
vmserver2 
vm-server-three.otherdomain.com 
server_four.domain.com 
server5 
server6 
some-silly-vm-name 
another_server.maybewithadomain.com 

Ausgang:

vmserver1 
vmserver2 
vm-server-three 
server_four 
server5 
server6 
some-silly-vm-name 
another_server 
0

Es gibt keine solche Dinge wie „voll qualifiziert“ oder „teilqualifizierten“ Hostnamen. Der Hostname ist der erste Teil einer URL nach dem Protokollnamen und sein Inhalt ist protokollabhängig und hostabhängig. Sie müssen definieren, was Sie meinen, bevor Sie reguläre Ausdrücke schreiben

Es ist leicht, Teile einer Zeichenkette geteilt durch Punkte zu trennen, aber Sie haben nicht spezifiziert, welches Teil oder Teile Sie wünschen. Es fühlt sich an, als würden Sie über verschiedene Arten von Zufallscode schreiben, in der Hoffnung, dass einer davon funktioniert

Dies ist nicht wirklich eine Antwort, und Sie werden nie eine richtige Lösung erhalten, bis Sie genau festgelegt haben, was Sie brauchen. Es ist sehr falsch, Dinge so lange auszuprobieren, bis Sie eine korrekte Ausgabe für Ihre Beispieleingabe erhalten. Ihre Software wirft das Geschäft Ihres Unternehmens, wenn Sie es so veröffentlichen. Ihr Code muss für jeden möglichen Eingang bearbeiten. Deshalb sollten Sie die Bedeutung Ihrer Forderung, statt nur die Worte und Ihre kleine Datenmenge

verstehen müssen, sind Sie ungarische Notation wie @aVmList zu verwenden gezwungen? Es ist nicht mehr sehr beliebt, und hat keinen Platz in Perl, wo die erste @ sagt, dass das Element ein Array ist, so a ist überflüssig und macht Ihr Programm weniger lesbar.Und es die Perl Art und Weise ist Großbuchstaben in Identifikatoren für lexikalische Variablen zu vermeiden, so dass Ihr Array viel besser wäre als @vm_list

Ihr erster Versuch

$_ =~ /(.*?)\./; 

ist identisch mit

/(.*?)\./; 

der tut nichts anderes als möglicherweise $1 Einstellung, wenn das Muster übereinstimmt. Sie scheinen den Zweck von $_ nicht begriffen zu haben, und es ist nicht der richtige Ort, um es hier vollständig zu erklären.

Vergessen Sie die Look-Around-Konstrukte. Als Erstes müssen Sie eine Regel definieren, die den erforderlichen Teil Ihres Hostnamens extrahiert. Wie machen Sie es, wenn Sie einen Hostnamen betrachten

Was passiert mit a.b.c.d.co.jp?

Was passiert mit a.b.c.vm-server-three.otherdomain.com.server_four.domain.com.co.uk?

Sie können diese nicht auf der Basis schreiben, dass Ihr Code solche Zeichenfolgen nie sehen wird. Wenn Sie nicht sicher sein können, dass sie bereits durch den aufrufenden Code bestätigt wurden, müssen Sie sie selbst überprüfen, bevor Sie versuchen, das entsprechende Teil zu extrahieren.