我在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 = $1;
print $sVmName;
}
我以为我需要使用后视点。我想出了以下
$_ =~ /([A-Za-z0-9-_]+)(?!=\.)/;
似乎在正则表达式测试程序中有效,但是当我运行我的Perl脚本时,它仍然匹配整个字符串。
我不喜欢上面使用正则表达式模式的路径,因为现在我假设主机名只包含“单词”字符或连字符。
我知道我不应该考虑主机名中的特殊字符,但我正在尝试将正则表达式模式基于匹配域名suffix.something.com
中第一个点之前的任何内容。
我还发现Regular expression to extract hostname from fully qualified domain name 这听起来像我想要的,但那里的建议似乎都没有。
我试过了:
$_ =~ (.+?)(?=\.)
和
$_ =~ ^([^.]+)\..*$
答案 0 :(得分:1)
否定字符类 [^...]
匹配除之外的任何字符。然后
my ($name) = $_ =~ /([^.]+)/;
匹配所有字符直到第一个.
并停在它处,因此没有理由明确匹配点(也不是该行的其余部分)。捕获匹配并将其分配给$name
。
在列表上下文中使用匹配运算符时,它将返回所有匹配项的列表
my @matches = $var =~ m/$pattern/g;
即使只有一个匹配项,我们也需要列表上下文以便返回匹配项,即my ($name) = ...
中的括号,以便在匹配运算符上强加列表上下文。在上面的例子中,这是通过分配一个数组来完成的。否则,我们会有标量上下文,在这种情况下,匹配运算符的行为会有所不同。请参阅此in perlop并查看perlretut。
上面的m
可能会被省略,最常见的是。但请注意,情况并非总是如此,例如使用不同的分隔符时。我建议您仔细阅读perlretut
。
循环中的默认输入和模式搜索空间($_
)包含当前处理的元素。默认情况下,正则表达式与$_
一起使用,因此无需指定$_
。请参阅General Variables in perlvar,并在perlop
链接中查看与正则表达式相关的评论。所以你可以做到
foreach (@vm_list) {
/([^.]+)/; # OK but better assign directly from the match
my $host_name = $1;
}
然而,直接从比赛中分配更清楚,如答案所示。
答案 1 :(得分: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
答案 2 :(得分:0)
没有“完全合格”或“部分合格”的主机名。主机名是协议名称后面的URL的第一部分,其内容依赖于协议和主机。在编写正则表达式模式之前,您必须定义您的意思
很容易将字符串的各个部分分开,但是您没有指定所需的部分。感觉就像是在撒谎,编写各种随机代码,希望其中一个可以工作
这不是一个真正的答案,在你确切地确定了你需要的东西之前,你永远不会得到一个合适的解决方案。在为样本输入获得正确的输出之前,继续尝试是非常错误的。如果您这样发布它,您的软件将会引发您公司的业务。您的代码必须用于它可能拥有的每个输入。这就是为什么你必须理解你的需求的含义而不仅仅是单词和少量数据
您是否被迫使用@aVmList
之类的匈牙利符号?它不再受欢迎,并且在Perl中没有位置,其中最初的@
表示该项是一个数组,因此a
是多余的,使您的程序可读性降低。在词法变量的标识符中避免使用大写字母是Perl的方法,所以你的数组会更好@vm_list
您的第一次尝试
$_ =~ /(.*?)\./;
与
相同/(.*?)\./;
如果模式匹配,除了可能设置$1
之外什么都不做。你似乎没有抓住$_
的目的,而且这里不能完全解释它
忘掉环顾四周的结构。您需要做的第一件事是定义一个 规则 ,它提取您所需的主机名部分。当你查看主机名
时,你如何做到这一点 a.b.c.d.co.jp
会怎样?
a.b.c.vm-server-three.otherdomain.com.server_four.domain.com.co.uk
会怎样?
你不能在你的代码永远不会看到这样的字符串的基础上写下这些。如果你不能确定它们已经被调用代码验证过,那么在尝试提取相应的部分之前,你必须自己检查它们。