nw_wind: (Камлать)
[personal profile] nw_wind
Немного програзма.

Операторы связи часто обмениваются друг с другом интервалами или диапазонами номеров. Например, диапазон это 4167700-4167899. А вот телефонные станции оперируют префиксами. То есть теми частями номера, которые в этом интервале не изменяются, в последующие цифры могут быть любыми. В вышеупомянутом примере это будет два префикса 41677 и 41678. Перелопачивать ручками десятки интервалов не самое интересное занятие, да и вероятность ошибки велика. Находясь в Ла Риохе (Испания) и под винными парами после дегустации замечательных напитков, я написал вот такую прелестную программку.

Кто поймёт как программа работает, тому зачёт. Написал со сторонним эффектом тк здесь он, мне кажется, вполне оправдан. Переменная dmax - это максимальная глубина погружения при поиске префиксов. Это можно вообще убрать. Я поставил тк мне стрёмно поведение рекурсивных алгоритмов с глубиной в десяток порядков.

На вход ей можно дать пары "начало:конец" интервалов с любыми разделителями. На выходе будут префиксы.

Программа распиливает диапазон на наименьшее возможное количество префиксов.

Пользуйтесь на здоровье. Не забывайте хвалить, размещать ссылки, рекомендовать товарищам, упоминать при использовании в ваших продуктах и платить роялти при использовании в продуктах коммерческих. Ибо GPL это.


#!/usr/bin/perl -w

# Sergei Keler (www.keler.net).
# Interval to Prefixes.

use strict;

# На входе пары типа начало:конец построчно
# Разделитель любой, :., таб - и пробел.
# На выходе префиксы.

my @r=(); # массив префиксов исключительно ради сортировки. Можно не использовать.
my $dpt=0;
my $dmax=1000000; # Максимальная глубина поиска.

# Просто читаем пары чисел с любым разделителем.
while (<>) {
  chomp;
  my ($s,$f)=split /[ \t:,.-]/;
  $dpt=0;
  maxint($s,$f); # преобразуем
}
# вывод.
foreach my $p (sort @r) {
  print "$p\n";
}

# Собственно логика тут.
sub maxint {
  my ($s,$f)=@_;
  
  return if $dpt++ > $dmax;
  if ($s == $f) {
    push @r,$s; # Можно print $s;
    return;
  }
  return if ($s > $f);
  if (($s % 10) != 0) {
    push @r,$s; # Можно print $s;
    return maxint($s+1,$f);
  }
  if (($f % 10) != 9) {
    push @r,$f; # Можно print $f;
    return maxint($s,$f-1);
  }
  return maxint(int($s/10), int($f/10));
}

Date: 2011-10-05 07:17 am (UTC)
From: [identity profile] baroho.livejournal.com
Ну кто знает перл тот поймет написанное. Видно, что под газом писал :)
Мне кажется можно укоротить раза в 3.

Date: 2011-10-05 08:08 am (UTC)
From: [identity profile] nw-wind.livejournal.com
наверное. предложи вариант.

Date: 2011-10-05 05:32 pm (UTC)
From: [identity profile] nw-wind.livejournal.com
Я думал как сделать красиво без стороннего эффекта, то есть без push @res,$var; У меня там в оригинале вообще print $var был. Не получилось без отжирания памяти и стека. Забил, так нормально. Укоротить это я не представляю реальным. Оно и так очень коротко. В принципе, наверное два return if первых объединить. Ну и всё.

Кстати, блаженство моего сотояния при написании проги видно по эти двум return if. Видно, что винные пары клубились в голове и сквозь них проступала логика.

Date: 2012-02-17 09:31 am (UTC)
From: [identity profile] sysmanone.livejournal.com
Полезно. Воспользовался. Спасибо.

Date: 2012-02-17 09:33 am (UTC)
From: [identity profile] nw-wind.livejournal.com
Ну, приятно, что труд не пропал зря. :-)
Ссылку на автора (сюда) плиз не забывайте, если что...

Date: 2012-02-17 09:45 am (UTC)
From: [identity profile] sysmanone.livejournal.com
соблюл. (с)opy пастнул как есть без купюр.

Date: 2012-02-17 10:18 am (UTC)
From: [identity profile] sysmanone.livejournal.com
Мне не за что.

Date: 2014-06-23 12:25 pm (UTC)
From: [identity profile] nw-wind.livejournal.com
Для IP-адресов:

Разбивает интервал адресов (в виде 32ных целых чисел) на минимальное количество подсетей.

#!/usr/bin/perl -w

# Sergei Keler (www.keler.net).
# Interval to Prefixes.

use strict;

# На входе пары типа начало:конец построчно
# Разделитель любой, :., таб - и пробел.
# На выходе префиксы.

my @r=(); # массив префиксов
my $dpt=0;
my $dmax=100000; # Максимальная глубина поиска.

while (<>) {
chomp;
my ($s,$f)=split /[ \t:,.-]/;
$dpt=0;
maxint($s,$f);
}
foreach my $p (sort @r) {
print "$p\n";
}

sub maxint {
my ($s,$f)=@_;

return if $dpt++ > $dmax;
if ($s == $f) {
push @r,$s;
return;
}
return if ($s > $f);
if (($s % 10) != 0) {
push @r,$s;
return maxint($s+1,$f);
}
if (($f % 10) != 9) {
push @r,$f;
return maxint($s,$f-1);
}
return maxint(int($s/10), int($f/10));
}

June 2017

S M T W T F S
    123
45678910
111213 1415 1617
18192021222324
252627282930 

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Apr. 7th, 2026 05:12 am
Powered by Dreamwidth Studios