【问题标题】:Perl create variables from substring of another variablePerl 从另一个变量的子字符串创建变量
【发布时间】:2014-03-27 14:23:15
【问题描述】:

我确信这可以使用split() 完成,但如果可能的话,我更感兴趣的是使用s//。我想将提供的 IP 地址与 IP 地址数组进行比较,并找到匹配项(如果存在)。我还想仅在整个元素(不是数组元素的子字符串)匹配时才认为部分匹配成功。

例如:提供的 IP:10.12.13.14

如果当前数组元素是 10.12。或 10. 或 10.12.13。我们可以认为这是一场比赛,但不是 10.12.11。

这是为了查找给定的 IP 是否存在于 Linux 主机上的 hosts.allow TCP 包装文件中。如果文件中没有包含地址,我将添加附加地址的功能。由于部分子网匹配 10.120。或 192.168。工作,我也需要测试这些。那就是我在下面缺少占位符“或子串匹配”的代码。我想知道 my $IP = "1.2.3.4"; 如何制作子字符串变量以便我可以对 "1.2.3.""1.2." 执行字符串比较?

#PSEUDO CODE EXAMPLE
my @IPS = (10.12.13.14, 191.168.1.2, 10.8., 172.16. );
my $IP = "10.8.3.44";
foreach (@IPS) { if( $IP eq $_ || split(/\d+\./, 1-3, $IP) eq $_ ) { print $IP matches current IP: $_\n} 
# That split is supposed to represent "10." "10.8." and "10.8.3."  That is the logic I am trying to accomplish, but I would like to use s// if it fits the job, otherwise I am open to split() or other suggestions

#REAL CODE EXAMPLE  
#!/usr/bin/perl

my $IP = $ARGV[0];
my $FILE = '/etc/hosts.allow';

# Make sure it is an IP with either 157. or 140. as first octet

unless ( $IP =~ qr/(140|157)\.(\d{1,3}\.){2}\d{1,3}/ ) {
die "Usage: $0 IP Address" } else {
    open (FH, "<", "$FILE");
    foreach $LINE (<FH>) {
        if ( $LINE =~ qr/^sshd: (.*)/i ) {
            @LIST = split(", ", $1);
            foreach (@LIST) { 
                chomp $_;
                if($IP eq $_) || (OR SUBSTRING MATCHES ) <-need code here {
                    print "IP ADDRESS: $IP found! \n";
                } else { print "$_ is not a match\n"};
            }
        }
    }
}

【问题讨论】:

标签: regex perl


【解决方案1】:

Why reinvent the wheel?

use strict;
use warnings;
use feature qw/say/;
use Net::Subnet;

my $allowed_hosts = subnet_matcher qw(
    10.8.0.0/16
    10.12.13.14/32
    191.168.1.2/32 
    172.16.0.0/16
);

for my $ip (qw/10.8.3.44/) {
    if ($allowed_hosts->($ip)) {
        say "$ip is allowed!";
    }
    else {
        say "$ip is disallowed!";
    }
}

【讨论】:

    【解决方案2】:

    您可以构建一个正则表达式来匹配您接受的列表。正如 M42 已经演示的那样,您需要使用 quotemeta 以便您的句点不被视为任何字符。您还需要注意边界条件:

    my @ips = qw(10.12.13.14 191.168.1.2 10.8. 172.16.);
    my $ips_list = join '|', map {/\d$/ ? "$_\$" : $_} map quotemeta, @ips;
    my $ips_re = qr{^(?:$ips_list)};
    
    while (<DATA>) {
        chomp;
        if ($_ =~ $ips_re) {
            print "(pass) $_\n";
        } else {
            print "(fail) $_\n";
        }
    }
    
    __DATA__
    10.8.3.44
    999.10.8.999
    10.12.13.14999
    10.12.13.14
    172.16.99.99
    191.168.1.2
    191.168.1.29
    

    输出:

    (pass) 10.8.3.44
    (fail) 999.10.8.999
    (fail) 10.12.13.14999
    (pass) 10.12.13.14
    (pass) 172.16.99.99
    (pass) 191.168.1.2
    (fail) 191.168.1.29
    

    【讨论】:

      【解决方案3】:

      怎么样:

      if ( ($IP eq $_) || ($IP =~ /^\Q$_/) )  {
      

      【讨论】:

      • 我不熟悉 \Q 正则表达式,你能解释一下吗?
      • 我设法查到了,我的连接速度很慢。看起来很有希望,我会测试一下。
      • 谢谢,我知道你的概念了。我的问题是我最初没有意识到 $_ 中有尾随空格。感谢您提供简单的解决方案。
      猜你喜欢
      • 1970-01-01
      • 2020-04-28
      • 2015-05-20
      • 2022-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多