Шукати в цьому блозі

вівторок, 6 серпня 2013 р.

Преобразование IPv4-адресов в Perl

К примеру, имеем такие массив и хеш:
my @array = ("127.0.0.1","212.90.160.8", "10.100.175.11", "10.10.10.8", "212.90.160.33","212.90.160.40");
my %hash = ("127.0.0.1" => "1", "212.90.160.8" => "0", "10.100.175.11" => "1", "10.10.10.8" => "1", "212.90.160.33" => "0", "212.90.160.40" => [ "1", "2" ] );
Хотим:
  • научиться быстренько преобразовывать каждый ip-адрес либо в числовой вид, либо просто в набор из четырёх байт;
  • хотим быстро, без лишних накладных расходов, вывести отсортированные значения ip-адресов из массива;
  • также хотим быстро, без лишних накладных расходов, вывести отсортированные значения ip-адресов, которые являются ключами хеша.
Преобразования из ip-адреса в число, из ip-адреса в набор символов и обратно можно осуществить, например, следующим образом:
map { 
    # Преобразовать ip-адрес в число
    my $n = unpack("N",pack("C4",split /\./));

    # Преобразовать число в ip-адрес
    print join(".",unpack("C4",pack("N",$n))),"\n";

    # Преобразовать ip-адрес в набор символов
    my $c = pack("C4",split /\./);

    # Преобразовать набор символов в ip-адрес
    print join(".",unpack("C4", $c)),"\n";
} @array;

Для того чтобы вывести отсортированный массив ip-адресов очевидным, однако не самым эффективным, является следующее решение:
foreach my $ip ( sort {
    my @a = split /\./, $a; my @b = split /\./, $b;
    return $a[0] <=> $b[0] || $a[1] <=> $b[1] || $a[2] <=> $b[2] || $a[3] <=> $b[3];
    } @array ) {
    printf("%s\n", $ip);
}
Используем другое, более элегантное решение, выведем отсортированный массив ip-адресов, при используя преобразование GRT (Guttman-Rosler Transform) для того чтобы избежать вызова пользовательской функции в sort. Подробнее об этом можно прочитать в Pragmatic Perl — Выпуск 4. Июнь 2013 в статье "Сортировка в Perl".
foreach my $ip ( map { join(".",unpack("C4")) } sort map { pack("C4",split /\./) } @array ) {
    printf("%s\n", $ip);
}

Для того чтобы отсортировать по ключу хеша слегка преобразуем предыдущий цикл:
foreach my $ip ( map { join(".",unpack("C4")) } sort map { pack("C4",split /\./) } keys %hash ) {
    printf("%s => %s\n", $ip, $hash{$ip});
}


Немає коментарів: