Perl正则表达式从主机名中提取机器名



我在CentOS 6.8 上使用Perl v5.1

我的程序将主机名列表读取到Perl数组@aVmList中。我试图只从它们中提取机器名称。

有些主机名是完全限定的,有些则不是。有些包含破折号或下划线。

我无法控制数组的内容。

以下是我正在使用的数据示例。

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
);

我只想从每个元素中提取机器名称,最后得到以下内容。

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

我找到了regex/(.*?)./,它几乎可以工作,但只有当所有名称都是完全限定的时。

foreach ( @aVmList ) {
$_ =~ /(.*?)./;
my $sVmName = $1;
print $sVmName;
}

我想我需要从背后看一下这些点。我想出了以下

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

这似乎在regex测试仪中有效,但当我运行Perl脚本时,它仍然匹配整个字符串。

我不喜欢上面regex模式的路径,因为现在我假设主机名只包含"word"字符或连字符。

我知道我不应该考虑主机名中的特殊字符,但我试图将正则表达式模式建立在匹配域名suffix.something.com中第一个点之前的任何内容的基础上。

我还找到了正则表达式来从完全限定域名中提取主机名,这听起来像我想要的,但那里的建议似乎都不起作用。

我试过了:

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

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

被否定的字符类[^...]匹配任何字符列出的字符除外。然后

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

匹配第一个.之前的所有字符,并在其处停止,因此没有理由显式匹配点(也没有理由匹配行的其余部分)。匹配被捕获并分配给$name


匹配运算符用于列表上下文时,它返回所有匹配的列表

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

即使只有一个匹配,我们也需要列表上下文,以便返回匹配,从而返回my ($name) = ...中的括号,以将列表上下文强加给匹配运算符。在上面的例子中,这是通过分配给一个数组来完成的。否则,我们将有标量上下文,在这种情况下,match运算符的行为不同。请参阅perlop和perlretut。

上面的m可以省略,而且通常是这样。但请注意,情况并非总是如此,例如,当使用不同的delimeter时。我建议好好阅读perlretut

循环中的默认输入和模式搜索空间($_)包含当前处理的元素。Regex默认情况下与$_一起使用,因此无需指定$_。请参阅perlvar中的General Variables,并参阅perlop链接中与正则表达式相关的注释。所以你可以做

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

然而,直接从比赛中分配更清楚,如答案中所示。

我认为这比它需要的更复杂

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

输出:

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

没有"完全限定"或"部分限定"的主机名。主机名是URL在协议名之后的第一部分,其内容依赖于协议和主机。在编写正则表达式模式之前,您必须定义您的意思

用点分隔字符串的各个部分很容易,但您还没有指定想要的一个或多个部分。感觉就像你在四处奔波,写各种各样的随机代码,希望其中一个能正常工作

这并不是一个真正的答案,除非你确定了自己的需求,否则你永远不会得到合适的解决方案。在得到正确的样本输入输出之前一直尝试是非常错误的。如果你这样发布你的软件,你公司的业务就会受到影响。您的代码必须为它可能拥有的每一个输入工作。这就是为什么你必须理解的意思你的要求,而不仅仅是单词和你的少量数据

你被迫使用像@aVmList这样的匈牙利符号吗?它不再流行了,在Perl中也没有位置,因为最初的@表示该项是一个数组,所以a是多余的,会降低程序的可读性。它是Perl避免在词法变量的标识符中使用大写字母的方法,因此您的数组将更好地用作@vm_list

您的第一次尝试

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

与相同

/(.*?)./;

其除了在模式匹配的情况下可能设置CCD_ 18之外什么也不做。你似乎还没有理解$_的目的,这里也不是完整解释它的地方

忘掉环视结构吧。您需要做的第一件事是定义规则,该规则提取主机名的必需部分。当你看到一个主机名时,你是如何做到的

a.b.c.d.co.jp发生了什么?

a.b.c.vm-server-three.otherdomain.com.server_four.domain.com.co.uk发生了什么?

你不能因为你的代码永远看不到这样的字符串就把它们写下来。如果您不能确定它们已经被调用代码验证,那么在尝试提取适当的部分之前,您必须亲自检查它们。