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