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

Perl regex to extract machine name from hostname

我在 CentOS 6.8 上使用 Perl v5.10

我的程序将主机名列表读入 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

我发现正则表达式 /(.*?)\./ 几乎可以工作,但只有在所有名称都完全限定时才可以。

foreach ( @aVmList ) {

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

    my $sVmName = ;

    print $sVmName;
}

我想我需要对这些点进行回顾。我想出了以下

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

这似乎在正则表达式测试器中工作,但是当我 运行 我的 Perl 脚本时它仍然匹配整个字符串。

我不喜欢我使用上面的正则表达式模式的路径,因为现在我假设主机名将只包含 "word" 个字符或一个连字符。

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

我也找到了Regular expression to extract hostname from fully qualified domain name 这听起来像我想要的,但那里的建议似乎都没有用。

我试过了:

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

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

否定字符 class [^...] 匹配任何字符 除了 列出的字符。那么

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

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


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

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

即使只有一个匹配项,我们也需要列表上下文以便返回匹配项,因此 my ($name) = ... 中的括号将列表上下文强加于匹配运算符。在上面的示例中,这是通过分配给数组来完成的。否则我们会有 标量上下文 ,在这种情况下,匹配运算符的行为会有所不同。看到这个 in perlop and see perlretut.

上面的m可能会被省略,而且最常见的是。但请注意,情况并非总是如此,例如当使用不同的分隔符时。我建议好好通读 perlretut.

循环中的 默认输入和模式搜索 space ($_) 包含当前处理的元素。默认情况下,正则表达式适用于 $_,因此无需指定 $_。请参阅 General Variables in perlvar,并在 perlop link 中查看与正则表达式相关的注释。所以你可以做

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

不过,直接从匹配中赋值会更清楚,如答案。

我认为你把事情弄得比需要的更复杂了。按句点拆分并使用第一部分:

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

没有 "fully-qualified" 或 "partially-qualified" 主机名。主机名是协议名后的URL的第一部分,其内容为protocol-dependent和host-dependent。在编写正则表达式模式之前必须定义你的意思

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

这并不是一个真正的答案,除非您确定了您所需要的内容,否则您永远不会得到合适的解决方案。在获得样本输入的正确输出之前不断尝试是非常错误的。如果您那样发布您的软件,您的公司将失去业务。您的代码必须 对它可能拥有的每个输入有效 。这就是为什么您必须理解您的要求的含义,而不仅仅是文字和少量数据

您是否被迫使用像 @aVmList 这样的匈牙利符号?它不再很流行,并且在 Perl 中没有位置,其中初始 @ 表示该项目是一个数组,因此 a 是多余的并且使您的程序可读性降低。这是避免在词法变量的标识符中使用大写字母的 Perl 方法,因此您的数组会更好 @vm_list

你的第一次尝试

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

等同于

/(.*?)\./;

除了可能设置 </code> 如果模式匹配,它什么都不做。你好像没领会<code>$_的目的,这里就不详细解释了

忘记 look-around 构造。您需要做的第一件事是定义一个 rule 来提取主机名的所需部分。当你看一个主机名时,你是怎么做到的

a.b.c.d.co.jp 会怎样?

a.b.c.vm-server-three.otherdomain.com.server_four.domain.com.co.uk 会怎样?

您不能因为您的代码永远不会看到此类字符串而将其注销。如果您不能确定它们是否已被调用代码验证,那么您必须在尝试提取适当的部分之前自行检查它们。