challenge IPv4アドレスのマスクの変換

  • "255.255.255.0" から 24
  • "255.255.255.128" から 25
  • "255.255.255.255" から 32

などのようにネットマスクの数値への変換を作ってみてください。

出来れば逆変換も作ってみてください。

Posted feedbacks - Flatten

Nested Hidden

SQL Server 2008 で確認しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
WITH
  Input(id, subnetmask) AS (
    SELECT 1, '255.255.255.0'
    UNION ALL SELECT 2, '255.255.255.128'
    UNION ALL SELECT 3, '255.255.255.255'
  )
, Input_(id, subnetmask) AS (
    SELECT id, subnetmask + '.' FROM Input
  )
, ToNums(id, i, element, input) AS (
    SELECT
        id
      , 1
      , CAST(LEFT(subnetmask, CHARINDEX('.', subnetmask, 1) - 1) AS int)
      , SUBSTRING(subnetmask, CHARINDEX('.', subnetmask, 1) + 1, LEN(subnetmask))
    FROM
        Input_
    UNION ALL
    SELECT
        id
      , i + 1
      , CAST(LEFT(input, CHARINDEX('.', input, 1) - 1) AS int)
      , SUBSTRING(input, CHARINDEX('.', input, 1) + 1, LEN(input))
    FROM
        ToNums
    WHERE
        i < 4
  )
, ToBin(id, i, bin, deci, crnt) AS (
    SELECT
        id
      , i
      , CAST(CASE
             WHEN element >= 128 THEN 10000000
                                 ELSE 0
             END AS bigint)
      , CASE
        WHEN element >= 128 THEN element - 128
                            ELSE element
        END
      , 6
    FROM
        ToNums
    UNION ALL
    SELECT
        id
      , i
      , CASE
        WHEN deci >= POWER(2, crnt) THEN POWER(10, crnt)
                                    ELSE 0
        END + bin
      , CASE
        WHEN deci >= POWER(2, crnt) THEN deci - POWER(2, crnt)
                                    ELSE deci
        END
      , crnt - 1
    FROM
        ToBin
    WHERE
        crnt >= 0
  )
, CountOne(id, result) AS (
    SELECT
        id
      , SUM(LEN(REPLACE(STR(bin, 8), '0', '')))
    FROM
        ToBin
    WHERE
        crnt = -1
    GROUP BY
        id
  )
SELECT id, result FROM CountOne

ふつーに実装。MASKアドレスじゃない場合のエラー処理とかは特にしてないです。

逆変換も付けました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
use strict;
use warnings;

sub addr2bits
{
  my ($addr) = @_;
  my $bits = 0;
  for (split /\./, $addr) {
    $_ &= 0xff;
    if ( 0xff == $_ ) {
      $bits += 8;
    }
    else {
      my $b = sprintf '%08b', $_;
      $bits += index($b,'0');
      last;
    }
  }
  $bits;
}

sub bits2addr
{
  my ($bits) = @_;

  my @addr;
  for ( 1 .. 4 ) {
    if ( $bits >= 8 ) {
      push @addr, 0xff;
      $bits -= 8;
    }
    elsif ( $bits > 0 ) {
      push @addr, oct('0b' . '1' x $bits . '0' x (8-$bits));
      $bits = 0;
    }
    else {
      push @addr, 0;
    }
  }
  join('.', @addr);
}

my $addr = $ARGV[0];
my $bits = addr2bits($addr);
print "$addr => $bits\n";

$addr = bits2addr($bits);
print "$bits => $addr\n";

C言語で。
netmask_to_prefix() : ネットマスク -> 数値
prefix_to_netmask() : 数値 -> ネットマスク
エラーの場合は-1を返却。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>

int netmask_to_prefix(char *s)
{
  unsigned long l;
  int b1, b2, b3, b4;
  int n;

  if (sscanf(s, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) == 4 && (b1 | b2 | b3 | b4) < 256) {
    l = (b1 << 24 | b2 << 16 | b3 << 8 | b4) ^ 0xffffffffUL;
    n = 32;
    while (l & 1) {
      n--;
      l >>= 1;
    }
    return l ? -1 : n;
  } else {
    return -1;
  }
}

int prefix_to_netmask(int n, char *s)
{
  unsigned long l;

  if (0 < n && n <= 32) {
    l = -1L << (32 - n);
    sprintf(s, "%d.%d.%d.%d",
      (int)(l >> 24 & 255), (int)(l >> 16 & 255), (int)(l >> 8 & 255), (int)(l & 255));
    return 0;
  } else {
    return -1;
  }
}

int main()
{
  char s[100];
  int n;

  printf("netmask? "); scanf("%s", s);
  printf("result: %d\n", netmask_to_prefix(s));

  printf("prefix? "); scanf("%d", &n);
  if (!prefix_to_netmask(n, s)) printf("result: %s\n", s);
}

もっとpackをかっこよく使いたい。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/perl
use strict;
use warnings;

sub maskstr2num{
    my $mask = shift;
    return if $mask !~ /^(\d{1,3}\.){3}\d+$/;
    my @mask_sections = split /\./,$mask;
    my $bit_mask = '';
    for(@mask_sections){
        return if $_ > 255;
        $bit_mask .= unpack("B8",pack("C",$_));
    }
    return if $bit_mask !~ /^1+0+$/;
    
    my $cnt = scalar(() = $bit_mask =~ /1/g);
    return $cnt;
}

sub num2maskstr{
    my $mask = shift;
    return if $mask > 32 || $mask < 0;
    $mask = '1'x$mask . '0'x(32-$mask);
    
    my @mask_sections = $mask =~ /^(\d{8})(\d{8})(\d{8})(\d{8})$/;
    $_ = unpack("C", pack("B8",$_)) for @mask_sections;
    
    $mask = join '.',@mask_sections;
    return $mask;
}

   a2m '255.255.255.0'
24
   a2m '255.255.255.128'
25
   a2m '255.255.255.255'
32
   m2a 24
255.255.255.0
   m2a 25
255.255.255.128
   m2a 32
255.255.255.255
1
2
a2m =: 3 : '+/ , #: ". > ''.'' cutopen y'
m2a =: 3 : '}: ; ,&''.'' @ ": each 256 #. inv #. 32 {. y # 1'

ビット演算で基本に忠実に実装しました。どのぐらいの長さになるか心配だったけど、そんなに悪くない行数で収まっています。

また、できるだけ例外処理をやって、さらにどのぐらい行が増えるかも試しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def netmask_num_of(addr):
    try:
        addrs = []
        for a in map(long, addr.split('.')):
            if a > 255 or a < 0: raise
            addrs.append(a)
        if len(addrs) != 4: raise
    except:
        raise "%s may not be an address string." % addr
    n = reduce(lambda a, b: a * 256 + long(b), addrs, 0)
    num = 0
    topbit = 1 << 31
    allbits = (1 << 32) - 1
    while n & topbit:
        num += 1
        n = (n << 1) & allbits
    if n:
        raise "%s is not valid for netmask." % addr
    return num

print netmask_num_of("255.255.255.0")
print netmask_num_of("255.255.255.128")
print netmask_num_of("255.255.255.255")

def netmask_str_of(num):
    if num > 32 or num < 0:
        raise "%s is out of range for netmask." % num
    n = 0L
    for i in range(32):
        n = (n << 1) | ((num > i) and 1 or 0)
    addrs = []
    for i in range(4):
        addrs.insert(0, str(n & 255))
        n = n >> 8
    return '.'.join(addrs)

print netmask_str_of(24)
print netmask_str_of(25)
print netmask_str_of(32)

エラー処理はしていません。
実行環境がRuby 1.8.6以前の場合
map(&:to_i) の部分を map{|e| e.to_i} にして下さい。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def mask2bits(mask_str)
  mask_str.split('.').map(&:to_i).inject(0){|r,e| 8.times{r+=(e&1);e>>=1};r}
end

def bits2mask(num)
  ['1'*num + '0'*(32-num)].pack('B*').unpack('C*')*'.'
end

if $0 == __FILE__
    puts mask2bits('255.255.255.0')
    puts mask2bits('255.255.255.128')
    puts mask2bits('255.255.255.255')
    puts bits2mask(24)
    puts bits2mask(25)
    puts bits2mask(32)
end

正変換は単に立っているビットの数を数えているだけ、逆変換は頭からビットを立たせているだけです。それだけしか出来ていないのに、ここで息切れしてしまいました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#load "str.cma"

let ni0 = Nativeint.zero;;
let ni1 = Nativeint.one;;
let (<<@) = Nativeint.shift_left;;
let (&@) = Nativeint.logand;;
let (|@) = Nativeint.logor;;

let netmask_num_of addr =
    let onbits_of byte = 
        let rec loop ptr =
            if ptr < 0 then 0 else
            let checker = ni1 <<@ ptr in
            if byte &@ checker = ni0 then 0 else
                1 + (loop (ptr - 1))
        in
            loop 7
    in
        let addrs = List.map Nativeint.of_string
            (Str.split (Str.regexp "\\.") addr) in
        List.fold_left (fun a b -> a + (onbits_of b)) 0 addrs 
;;
print_string ((string_of_int (
    netmask_num_of "255.255.255.0")) ^ "\n");;
print_string ((string_of_int (
    netmask_num_of "255.255.255.128")) ^ "\n");;
print_string ((string_of_int (
    netmask_num_of "255.255.255.255")) ^ "\n");;

let netmask_str_of num =
    let rec byteloop num n =
        if n = 0 then [] else
        let rec bitloop num b =
            if num = 0 or b < 0 then ni0 else
            (ni1 <<@ b) |@ (bitloop (num - 1) (b - 1))
        in
            [Nativeint.to_string (bitloop num 7)] @
                (byteloop (num - 8) (n - 1))
    in
        String.concat "." (byteloop num 4)
;;
print_string ((netmask_str_of 24) ^ "\n");;
print_string ((netmask_str_of 25) ^ "\n");;
print_string ((netmask_str_of 32) ^ "\n");;

  • Limboのキャストはtype exprのように書きます。
  • int "1"の場合、数値に変換してくれます。

極力、定数は使わないように書きました。 8(ビット数)は名前を思いつかなかったので。

テストコードも含めてみましたが、 かえって見づらくなっただけかもしれません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
implement Netmask;

include "sys.m";
    sys: Sys;
    fprint, sprint: import sys;
include "draw.m";

Netmask: module
{
    init: fn(nil: ref Draw->Context, argv: list of string);
};

IPv4len: con 4;

data := array[] of {
    ("255.128.0.0", 9),
    ("255.255.255.0", 24),
    ("255.255.255.128", 25),
    ("255.255.255.255", 32),
};

init(nil: ref Draw->Context, nil: list of string)
{
    sys = load Sys Sys->PATH;
    stderr := sys->fildes(2);

    for(i := 0; i < len data; i++){
        (addr, expected) := data[i];
        actual := toint(addr);
        if(actual != expected)
            fprint(stderr, "%s %d vs %d\n", addr, actual, expected);
        r := toaddr(expected);
        if(addr != r)
            fprint(stderr, "%d %s vs %s\n", expected, r, addr);
    }
}

toint(addr: string): int
{
    (n, l) := sys->tokenize(addr, ".");
    if(n != IPv4len)
        return -1;

    sum := 0;
    for(p := l; p != nil; p = tl p)
        sum += bitcount(byte hd p);
    return sum;
}

bitcount(b: byte): int
{
    sum := 0;
    for(n := int b; n; n &= n-1)
        sum++;
    return sum;
}

toaddr(n: int): string
{
    N: con IPv4len*8;

    if(n < 0 || n > N)
        return nil;
    t := (big 1 << n) - big 1;
    t <<= N-n;
    s := "";
    for(i := 0; i < IPv4len; i++)
        s += sprint(".%d", int byte (t >> (IPv4len-i-1)*8));
    return s[1:];
}

ちょっと汚いかな・・・

1
2
3
4
5
6
7
8
9
def toMask(ip){
    ip.split(/\./).collect{
        Integer.toBinaryString(it.toInteger())
    }*.count("1").sum()
}

assert toMask("255.255.255.0") == 24
assert toMask("255.255.255.128") == 25
assert toMask("255.255.255.255") == 32

F#で、
実行例
> maskstr2num "255.255.255.0";;
val it : int = 24
> maskstr2num "255.255.255.128";;
val it : int = 25
> maskstr2num "255.255.255.255";;
val it : int = 32
> num2maskstr 24;;
val it : string = "255.255.255.0"
> num2maskstr 25;;
val it : string = "255.255.255.128"
> num2maskstr 32;;
val it : string = "255.255.255.255"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let bitcount bits:int =
  let bits = (bits &&& 0x55555555) + (bits >>> 1 &&& 0x55555555)
  let bits = (bits &&& 0x33333333) + (bits >>> 2 &&& 0x33333333)
  let bits = (bits &&& 0x0f0f0f0f) + (bits >>> 4 &&& 0x0f0f0f0f)
  let bits = (bits &&& 0x00ff00ff) + (bits >>> 8 &&& 0x00ff00ff) in 
      (bits &&& 0x0000ffff) + (bits >>>16 &&& 0x0000ffff)

let maskstr2num (mask:string) =
  bitcount  <| Seq.fold ( fun a b -> a * 256 + int b ) 0 (mask.Split('.'))

let num2maskstr (num:int) =
  let unum = uint32 (2.0 ** (float num))-1u <<< (32-num)
  System.String.Join(".", [|for i=3 downto 0 do yield ((unum &&& (0xFFu <<< i*8) >>> i*8).ToString()) |])

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(use srfi-1)
(use util.list)

(define (mask->nbits mask)
  (count (cut eqv? #¥1 <>)
         (append-map (lambda (n) (string->list (format "~b" (string->number n))))
                     (string-split mask #¥.))))

(define (nbits->mask nbits)
  (string-join (map (lambda (bits) #`",(string->number (list->string bits) 2)")
                    (slices (take* (make-list nbits #¥1) 32 #t #¥0) 8))
               "."))

やった、処理が80文字に収まった!

oct()が2進数文字列を変換できるのはあまり知られていない気がします。

1
2
3
4
5
6
7
use List::Util qw/sum/;
sub mask2bits($) {
  sum map { split //, sprintf '%b', $_ } split /\./, shift;
}
sub bits2mask($) {
  join '.', map { oct "0b$_" } (1 x $_[0] . 0 x (32 - $_[0])) =~ /\d{8}/g;
}

x86のBSF命令 (下から数えて何ビット目が立っているか) を使ってみました。
また、uintは4バイト固定です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import std.intrinsic: bsf;      // x86's BSF instruction
import std.socket;

immutable ushort DUMMY_PORT = 0;

uint mask2bits(in string mask)
{
    uint addr = (new InternetAddress(mask, DUMMY_PORT)).addr;
    return 32 - bsf(addr);
}

string bits2mask(in uint bits)
{
    uint addr = 0xFFFF_FFFF << (32 - bits);
    return (new InternetAddress(addr, DUMMY_PORT)).toAddrString;
}

void main()
{
    assert (mask2bits("255.255.255.0") == 24);
    assert (mask2bits("255.255.255.128") == 25);
    assert (mask2bits("255.255.255.255") == 32);
    assert (bits2mask(24) == "255.255.255.0");
    assert (bits2mask(25) == "255.255.255.128");
    assert (bits2mask(32) == "255.255.255.255");
}

とりあえず、InetAddressを使いました。例外処理があるので効率は・・・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.net._

object IPNetMask {
  val ipMask2NumBits = Map(
       (256-  1) -> 8 ,
       (256-  2) -> 7 ,
       (256-  4) -> 6 ,
       (256-  8) -> 5 ,
       (256- 16) -> 4 ,
       (256- 32) -> 3 ,
       (256- 64) -> 2 ,
       (256-128) -> 1 ,
               0 -> 0 )
  var ipNumBits2Mask = Map[Int,Int]()
  for( (k,v)<-ipMask2NumBits ) ipNumBits2Mask += v->k
  
  def main(args : Array[String]) : Unit = {
    //ipMask2NumBits.foreach(println _)
    //ipNumBits2Mask.foreach(println _)
    
    for{ arg <-args
         ip  =InetAddress.getByName(arg) }{
      ip2numbits(ip) match {
        case Some(n) =>
          println(ip+" : " +n+"bits")
          println("reverse : "+numbits2ip(n))
        case None => println("error")
      }
    }
    
    ()
  }
  def ip2numbits(ip:InetAddress) : Option[Int] = {
    val rawIP = ip.getAddress.map(0x0FF & _)
    try{
      rawIP match{
        case Seq(255,255,255,a) => return Some( 24 + ipMask2NumBits(a) )
        case Seq(255,255,  a,0) => return Some( 16 + ipMask2NumBits(a) )
        case Seq(255,  a,  0,0) => return Some(  8 + ipMask2NumBits(a))
        case _ => return None
      }
    }catch{
      case _ => return None
    }
    None
  }
  
  def numbits2ip(numbits:Int) : Option[InetAddress]={
    try{
      numbits match {
        case n if (n >= 24) => return Some(InetAddress.getByName( ipNumBits2Mask(n-24).formatted("255.255.255.%d")))
        case n if (n >= 16) => return Some(InetAddress.getByName( ipNumBits2Mask(n-16).formatted("255.255.%d.0")))
        case n if (n >=  8) => return Some(InetAddress.getByName( ipNumBits2Mask(n- 8).formatted("255.%d.0.0")))
      }
    }catch{
      case _ => return None
    }
    None
  }
}

「ipaddr2mask」でアドレス→数値変換。 「mask2ipaddr」で数値→アドレス変換。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function format(num, dec1, dec2, minlen){
    var num1 = new Number(parseInt(num, dec1)).toString(dec2);;
    while(num1.length < minlen) num1 = "0" + num1;
    return num1;
}

function ipaddr2mask(ipaddr){
    var ad = ipaddr.split(".");
    var str = "";
    for(var i = 0; i < ad.length; i++){
        str += format(ad[i],10,2,8);
    }
    for(var i = str.length-1; i > 0 ; i--){
        if(str.charAt(i)!=0){return i+1;}
    }
    return 0;
}

function mask2ipaddr(mask){
    var m1 = format(mask,10,10,1);
    var str = "";
    while(str.length < 32){ str+= (str.length < m1) ? "1" : "0"; }
    var ipaddr = "";
    for(var i = 0; i < 4; i++){
        if(i > 0){ ipaddr+="."; }
        ipaddr+=format(str.substr(i*8, 8),2,10,1);
    }
    return ipaddr;
}

結構乱暴。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <algorithm>
#include <functional>
#include <bitset>
#include <string>
#include <sstream>
#include <cassert>

int mask2bits(const std::string& s)
{
    int  n[4];
    char c[3];

    if( (std::istringstream(s) >> n[0] >> c[0] >> n[1] >> c[1] >> n[2] >> c[2] >> n[3]) &&
        (std::count(c, c + 3, '.') == 3)                                                &&
        (std::count_if(n, n + 4, std::bind1st(std::less_equal<int>(), 0)) == 4)         &&
        (std::count_if(n, n + 4, std::bind2nd(std::less_equal<int>(), 255)) == 4)       )
    {
        return std::bitset<32>((n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3]).count();
    }
    else
    {
        return -1;
    }
}

std::string bits2mask(int n)
{
    if((0 <= n) && (n <= 32))
    {
        std::bitset<32> bits;
        for(int i = 0; i < n; ++i)
        {
            bits.set(31 - i);
        }
        unsigned long m = bits.to_ulong();
        std::ostringstream oss;
        oss << ((m >> 24) & 0xffu) << '.' << ((m >> 16) & 0xffu) << '.' << ((m >> 8) & 0xffu) << '.' << (m & 0xffu);
        return oss.str();
    }
    else
    {
        return "";
    }
}

int main(int, char* [])
{
    assert (mask2bits("255.255.255.0")   == 24);
    assert (mask2bits("255.255.255.128") == 25);
    assert (mask2bits("255.255.255.255") == 32);
    assert (bits2mask(24) == "255.255.255.0");
    assert (bits2mask(25) == "255.255.255.128");
    assert (bits2mask(32) == "255.255.255.255");

    return 0;
}

Squeak Smalltalk で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
| maskStrToBits |
maskStrToBits := [:maskStr |
    ((maskStr subStrings: '.') collect: [:each | each asInteger radix: 2]) 
        concatenation occurrencesOf: $1].

maskStrToBits value: '255.255.255.0'.     "=> 24 "
maskStrToBits value: '255.255.255.128'.   "=> 25 "
maskStrToBits value: '255.255.255.255'.   "=> 32 "


| bitsToMaskStr |
bitsToMaskStr := [:int |
    String streamContents: [:ss |
        (((String new: int withAll: $1) forceTo: 32 paddingWith: $0)
                groupsOf: 8 atATimeCollect: [:each | ('2r', each) asNumber printString])
            do: [:each | ss nextPutAll: each] separatedBy: [ss nextPut: $.]]].

bitsToMaskStr value: 24.   "=> '255.255.255.0' "
bitsToMaskStr value: 25.   "=> '255.255.255.128' "
bitsToMaskStr value: 32.   "=> '255.255.255.255' "

すみません、昨日無駄にNativeintを使ったあげく、末尾再帰最適化されないコードを書いてしまいました。同じアルゴリズムをより正しく実装したものがこっちです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#load "str.cma"

let print_string_nl v = print_string (v ^ "\n")
let print_int_nl v = print_string_nl (string_of_int v)

let netmask_num_of addr =
    let onbits_of byte = 
        let rec loop ptr v =
            if ptr < 0 || byte land (1 lsl ptr) = 0 then v
            else loop (ptr - 1) (v + 1)
        in loop 7 0
    in
    let addrs = List.map int_of_string (Str.split (Str.regexp "\\.") addr) in
    List.fold_left (fun a b -> a + (onbits_of b)) 0 addrs 
;;
print_int_nl (netmask_num_of "255.255.255.0");;
print_int_nl (netmask_num_of "255.255.255.128");;
print_int_nl (netmask_num_of "255.255.255.255");;

let netmask_str_of num =
    let rec byteloop num n v =
        if n = 0 then v
        else
            let rec bitloop num b v =
                if num = 0 or b < 0 then v
                else bitloop (num - 1) (b - 1) ((1 lsl b) lor v)
            in byteloop (num - 8) (n - 1) (v @ [string_of_int (bitloop num 7 0)])
    in String.concat "." (byteloop num 4 [])
;;
print_string_nl (netmask_str_of 24);;
print_string_nl (netmask_str_of 25);;
print_string_nl (netmask_str_of 32);;

ナイーブに。

 *Main> mask2nbits "255.255.255.0"
 24
 *Main> mask2nbits "255.255.255.128"
 25
 *Main> mask2nbits "255.255.255.255"
 32
 *Main> nbits2mask 24
 "255.255.255.0"
 *Main> nbits2mask 25
 "255.255.255.128"
 *Main> nbits2mask 28
 "255.255.255.240"
 *Main> nbits2mask 32
 "255.255.255.255"

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import Data.List
import Data.Word

mask2nbits :: String -> Int
mask2nbits = length . takeWhile (1==) . toNArry 2 32 . addr2int 

nbits2mask :: Int -> String
nbits2mask n = int2addr $ maxBound - (2^(32-n)-1)

int2addr :: Word32 -> String
int2addr = concat . intersperse "." . map show . toNArry 256 4

addr2int :: String -> Word32
addr2int = foldl ((+) . (256 *)) 0 . unfoldr phi
  where 
    phi "" = Nothing
    phi s  = case break ('.'==) s of
               (xs,_:ys) -> Just (read xs,ys)
               (xs,[])   -> Just (read xs,[])

toNArry :: (Integral i) => Int -> Int -> i -> [Int]
toNArry n k i 
 = map fromInteger 
 $ snd 
 $ mapAccumR (flip id) (toInteger i) (replicate k (`divMod` (toInteger n)))

変換・逆変換の過程をたどりやすくしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import Data.Word        ( Word32, Word8 )
import Data.List        ( unfoldr, intersperse )

-- Int <-> String
nbits2mask = str_w8s . w8s_w32 . w32_int
mask2nbits = int_w32 . w32_w8s . w8s_str

-- Int <-> Word32
w32_int = (maxBound-) . (-1+) . (2^) . (32-)
int_w32 = (32-) . round . logBase 2 . (1+) . fromIntegral . (maxBound-)

-- Word32 <-> [Word8]
w8s_w32 = reverse . take 4 . map w8_w32 . unfoldr (Just . swap . (`divMod`256))
w32_w8s = foldl ((+) . (256*)) 0 . map w32_w8

-- [Word8] <-> String
str_w8s = concat . intersperse "." . map show
w8s_str = map read . unfoldr phi . ('.':)
  where
    phi []     = Nothing
    phi (_:cs) = Just $ break ('.'==) cs


-- misc
swap (x,y) = (y,x)

w8_w32 = toEnum . fromEnum :: Word32 -> Word8           -- 0 <= arg < 2^8
w32_w8 = toEnum . fromEnum :: Word8  -> Word32          -- 0 <= arg < 2^8

main = mapM_ (print . test) [0..32]
  where
    test n = let { m = nbits2mask n; n' = mask2nbits m } in (n, m, n==n')

PPCRE を使ってみました。逆はビット演算で。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(asdf:operate 'asdf:load-op :cl-ppcre)

(defun mask-to-bits (s)
  (position #\0 (format nil "~{~8,'0B~}0"
                        (mapcar #'parse-integer (ppcre:split "\\." s)))))

(defun bits-to-mask (n)
  (let ((m (deposit-field #xffffffff (byte n (- 32 n)) 0)))
    (format nil "~D.~D.~D.~D"
            (ldb (byte 8 24) m) (ldb (byte 8 16) m)
            (ldb (byte 8 8) m) (ldb (byte 8 0) m))))

InetAddressを引数にしてネットマスクのbit数を返すメソッドと、bit数からInet4Address を返すメソッドです。ネットマスクが n bit の時、ビットパターンが2の補数表現で -2^(32 - n) になる事を利用しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.net.*;
import java.math.*;
import java.io.*;

public class Sample {

    public static int maskLength(InetAddress adrs) {
        BigInteger a = new BigInteger(adrs.getAddress());
        if (a.bitCount() != a.bitLength())
            throw new IllegalArgumentException("Illegal mask.");
        return 8 * adrs.getAddress().length - a.bitCount();
    }
    
    public static InetAddress getMask(int n) {
        try {
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(bs);
            dos.writeInt(-(1 << (32 - n)));
            return Inet4Address.getByAddress(bs.toByteArray());
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
    
    public static void main(String[] args) throws UnknownHostException {
        System.out.println(maskLength(InetAddress.getByName("255.255.255.0")));
        System.out.println(maskLength(InetAddress.getByName("255.255.255.128")));
        System.out.println(maskLength(InetAddress.getByName("255.255.255.255")));
        System.out.println(maskLength(InetAddress.getByName("ffff:ffff:ffff::")));
        System.out.println(getMask(24));
        System.out.println(getMask(25));
        System.out.println(getMask(32));
    }

}

#9133の移植です。
便利なクラスがあるんですねえ。
勉強になりました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Java版(#9133)の移植です。
import java.net._
import java.math._
import java.io._

object IPNetMask9133 {
  def main(args : Array[String]) : Unit = {
    System.out.println(maskLength(InetAddress.getByName("255.255.255.0")));
    System.out.println(maskLength(InetAddress.getByName("255.255.255.128")));
    System.out.println(maskLength(InetAddress.getByName("255.255.255.255")));
    System.out.println(maskLength(InetAddress.getByName("ffff:ffff:ffff::")));
    System.out.println(getMask(24));
    System.out.println(getMask(25));
    System.out.println(getMask(32));
  }
  
  def maskLength(adrs:InetAddress):Int = {
    val a = new BigInteger(adrs.getAddress());
    if (a.bitCount() != a.bitLength())
       throw new IllegalArgumentException("Illegal mask.")
    //
    return 8 * adrs.getAddress().length - a.bitCount();
  }
  
  def getMask(n:Int) :InetAddress = {
    try {
      val bs = new ByteArrayOutputStream();
      val dos = new DataOutputStream(bs);
      dos.writeInt(-(1 << (32 - n)));
      return InetAddress.getByAddress(bs.toByteArray());
    } catch {
      case e:Exception =>throw new IllegalStateException(e);
    }
  }
}

Scala(#9133)をErlangに移植しました。 効率はともかく、例外処理をしているので・・・

関数の仕様は、Erlang的で、成功時は {ok,****} のようなタプルが返ります。失敗時はok以外のアトム。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
-module(netmask).
-export([numbits_of/1,from_numbits/1,test/0]).

numbits_of(StrMask) -> 
    try
        {ok,Mask} = inet_parse:address(StrMask) ,
        {Class,MaskByte} = case Mask of
                        {255,255,255,X} -> {24,X};
                        {255,255,  X,0} -> {16,X};
                        {255,  X,  0,0} -> { 8,X};
                        _ -> throw("bad mask")
                        end,
        {ok,
        case MaskByte of
            (256-  1)-> 8;
            (256-  2)-> 7;
            (256-  4)-> 6;
            (256-  8)-> 5;
            (256- 16)-> 4;
            (256- 32)-> 3;
            (256- 64)-> 2;
            (256-128)-> 1;
            0        -> 0
        end + Class }% <--- result
    catch
        throw:E -> {thrown,E};
        exit :E -> {exited,E};
        error:E -> {error ,E}
    end.

from_numbits(Numbits)->
    try
        {Class,Maskbits} = 
                        case Numbits of
                            N when N>=24 -> {24,N-24} ;
                            N when N>=16 -> {16,N-16} ;
                            N when N>= 8 -> { 8,N- 8} 
                        end ,
        Maskbyte = 
                case Maskbits of 
                    8 -> (256-  1) ;
                    7 -> (256-  2) ;
                    6 -> (256-  4) ;
                    5 -> (256-  8) ;
                    4 -> (256- 16) ;
                    3 -> (256- 32) ;
                    2 -> (256- 64) ;
                    1 -> (256-128) ;
                    0 -> 0
                end ,
        %
        {ok , 
        case Class of
            24 -> inet_parse:ntoa( {255,255,255,Maskbyte} ) ;
            16 -> inet_parse:ntoa( {255,255,Maskbyte  ,0} ) ;
            8  -> inet_parse:ntoa( {255,Maskbyte    ,0,0} ) 
        end }% <--- result
    catch
        throw:E -> {thrown,E};
        exit :E -> {exited,E};
        error:E -> {error ,E}
    end.

test()->
    lists:foreach(fun(I)->
                    {ok , M} = from_numbits(I),
                    {ok , N} = numbits_of(M),
                    io:format("Numbits=~p , Mask=~p , Result=~p~n",[I,M,(I==N)])
                  end , lists:seq(8,31) ).

string→intの変換のみ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class P
{
  static int ToI(string mask)
  {
    try
    {
      string[] a = mask.Split('.');
      if (a.Length != 4) return -1;
      long l = a.Aggregate(1L, (x, y) => (x << 8) + Convert.ToByte(y));
      string b = Convert.ToString(l, 2).Substring(1, 32);
      int p = b.IndexOf('0');
      return p < 0 ? 32 : b.IndexOf('1', p) < 0 ? p : -1;
    }
    catch
    {
      return -1;
    }
  }
}

無味乾燥。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function mask2bits($ddn_str)
{
    $bits = 0;
    $decs = explode('.', $ddn_str);
    foreach ( $decs as $dec ) {
        $bits += substr_count(decbin($dec), '1');
    }
    return $bits;
}

function bits2mask($bits)
{
    $bits_str = strrev(sprintf('%032s', str_repeat("1", $bits)));
    $bins = str_split($bits_str, 8);
    foreach ($bins as $bin) {
        $decs[] = bindec($bin);
    }
    return implode('.', $decs);
}

Squirrel3.0で。
bits2mask()のbits=0の時が美しくない・・・
(1<<32が1になってしまう。64bitなら無視できるかも)
結果:
        0.0.0.0 =>  0
      128.0.0.0 =>  1
  255.255.255.0 => 24
255.255.255.128 => 25
255.255.255.255 => 32
 0 =>         0.0.0.0
 1 =>       128.0.0.0
 8 =>       255.0.0.0
32 => 255.255.255.255
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function mask2bits(mask)
{
    local addr = split(mask, ".").reduce(@(a,b) (a.tointeger()<<8) + b.tointeger());
    for(local i=32; addr; i--, addr=addr>>1) if (addr&1) return i;
    return 0;
}
function bits2mask(bits)
{
    local addr = bits ? -(1<<(32-bits)) : 0;
    return format("%d.%d.%d.%d", addr>>24&0xFF, addr>>16&0xFF, addr>>8&0xFF, addr>>0&0xFF);
}

function test_mask2bits(mask)
{
    print(format("%15s => %2d\n", mask, mask2bits(mask)));
}
function test_bits2mask(bits)
{
    print(format("%2d => %15s\n", bits, bits2mask(bits)));
}

test_mask2bits("0.0.0.0");
test_mask2bits("128.0.0.0");
test_mask2bits("255.255.255.0");
test_mask2bits("255.255.255.128");
test_mask2bits("255.255.255.255");

test_bits2mask(0);
test_bits2mask(1);
test_bits2mask(8);
test_bits2mask(32);

Javaでシンプルに。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
public class SubnetMask {
    
    public static void main( String[] args ) {
        System.out.println( getMaskLength( "255.255.255.0" ) );
        System.out.println( getMaskLength( "255.255.255.128" ) );
        System.out.println( getMaskLength( "255.255.255.255" ) );
        System.out.println( getMask( 24 ) );
        System.out.println( getMask( 25 ) );
        System.out.println( getMask( 32 ) );
    }
        
    // サブネットマスクの長さを求める。
    public static int getMaskLength( String subnetMask ) {
        
        /////////////////////////////////////////////////////////////
        // サブネットマスクの妥当性確認
        /////////////////////////////////////////////////////////////

        // サブネットマスクが「数値.数値.数値.数値」の形式であることを確認する。
        if ( ! subnetMask.matches( "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+" ) ) {
            throw new RuntimeException( "指定されたサブネットマスクが不正です。" );
        }

        // サブネットマスクの数値が以下の順に並んでいることを確認する。
        // 1. 255が0個以上
        // 2. 254と252と248と240と224と192と128のいずれかが0個か1個
        // 3. 0が0個以上」
        String temp = subnetMask + ".";
        if ( ! temp.matches( "(255\\.)*((254|252|248|240|224|192|128)\\.)?(0\\.)*" ) ) {
            throw new RuntimeException( "指定されたサブネットマスクが不正です。" );
        }

        /////////////////////////////////////////////////////////////
        // サブネットマスクを長さに変換
        /////////////////////////////////////////////////////////////

        // サブネットマスクを4つの数値に分割する。
        String[] partsStr = subnetMask.split( "\\." );
        int[] parts = new int[4];
        for ( int i = 0; i < 4; ++i ) {
            parts[i] = Integer.parseInt( partsStr[i] );
        }
            
        // 各数値のビット数を求め、ビット数を合計して長さを求める。
        int result = 0;
        for ( int i = 0; i < 4; ++i ) {
            switch ( parts[i] ) {
                case 255:
                    result += 8;
                    break;
                case 254:
                    result += 7;
                    break;
                case 252:
                    result += 6;
                    break;
                case 248:
                    result += 5;
                    break;
                case 240:
                    result += 4;
                    break;
                case 224:
                    result += 3;
                    break;
                case 192:
                    result += 2;
                    break;
                case 128:
                    result += 1;
                    break;
                case 0:
                    result += 0;
                    break;
            }
        }
            
        return result;
    }

    // 長さからサブネットマスクを求める。
    public static String getMask( final int length ) {
        
        /////////////////////////////////////////////////////////////
        // 長さの妥当性確認
        /////////////////////////////////////////////////////////////
        
        if ( length < 0 || 32 < length ) {
            throw new RuntimeException( "指定された長さが不正です。" );
        }

        /////////////////////////////////////////////////////////////
        // 長さをサブネットマスクに変換
        /////////////////////////////////////////////////////////////
        
        // サブネットマスクの4つ数値
        int[] parts = new int[] { 0, 0, 0, 0 };
        
        // 4つ数値のうち、先頭から「長さを8で割った商」個の数値を255にする。
        int q = length / 8;
        for ( int i = 0; i < q; ++i ) {
            parts[i] = 255;
        }
        
        // 「長さを8で割った余り」がある場合、
        // 4つの数値のうち、先頭から「長さを8で割った商 + 1」番目の数値を、「余り」から求める。
        int r = length % 8;
        switch ( r ) {
            case 7:
                parts[q] = 254;
                break;
            case 6:
                parts[q] = 252;
                break;
            case 5:
                parts[q] = 248;
                break;
            case 4:
                parts[q] = 240;
                break;
            case 3:
                parts[q] = 224;
                break;
            case 2:
                parts[q] = 192;
                break;
            case 1:
                parts[q] = 128;
                break;
        }
        
        // 4つの数値を連結して、サブネットマスクを作成する。
        return parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3];
    }
}

・Mask2Bit:
  ネットマスク(文字型)を渡すとビット値(数値型)を返却します。
・Bit2Mask:
  ビット値(数値型)を渡すとネットマスク(文字型)を返却します。

/* ネットマスクをビット値に変換 */
call Mask2Bit input("input netmask.");
message str(##return);

/* 逆変換 */
call Bit2Mask val(input("input value."));
message $$return;

* パラメータの妥当性はチェックしてません。
* Bin2DecとDec2Binは2進数⇔10進数のサブルーチンです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Mask2Bit:
    ##c=0;
    ##bit=0;
    while (strlen($$1)) {
        $b = leftstr($$1,1);
        $$1 = rightstr($$1, strlen($$1)-1);
        if ($b == ".") {
            ##c = ##c + 1;
        } else if (val($b) == 0 && $b != "0") {
            break;
        } else {
            $$aar[##c] = $$aar[##c] + $b;
        }
    }
    while (0 <= ##c) {
        call Dec2Bin val($$aar[##c]);
        while (strlen($$return)) {
            ##bit = ##bit + val(leftstr($$return,1));
            $$return = rightstr($$return, strlen($$return)-1);
        }
        ##c = ##c - 1;
    }
    return ##bit;

Bit2Mask:
    $$b_str = "";
    $$mask = "";
    while (strlen($$b_str) < 32) {
        if (0<##1) {
            $$b_str = $$b_str + "1";
        } else {
            $$b_str = $$b_str + "0";
        }
        ##1 = ##1 - 1;
    }
    while (strlen($$b_str)) {
        call Bin2Dec leftstr($$b_str, 8);
        $$mask = $$mask + str(##return);
        $$b_str = rightstr($$b_str, strlen($$b_str)-8);
        if (strlen($$b_str)) {
            $$mask = $$mask + ".";
        }
    }
    return $$mask;

Bin2Dec:
    ##dec = 0;
    ##val = 1;
    while (strlen($$1)) {
        if (rightstr($$1, 1) == "1") {
            ##dec = ##dec + ##val;
        }
        ##val = ##val*2;
        $$1 = leftstr($$1, strlen($$1)-1);
    }
    return ##dec;

Dec2Bin:
    $$str = "";
    if (##1!=0) {
        while (##1!=1) {
            $$str = str(##1%2)+$$str;
            ##1 = ##1/2;
        }
        $$str = "1"+$$str;
    } else {
        $$str = "0";
    }
    return $$str;

人のを見ないで作ってみた。ドキドキ。

1
2
3
4
5
6
7
def netMask(addr) {
  Long.toString(addr.split(/\./).inject(0) {a,b->a*256+(b as long)},2).chars.grep{it=='1'}.size()
}

assert netMask("255.255.255.0")==24
assert netMask("255.255.255.128")==25
assert netMask("255.255.255.255")==32

Groovyでの逆変換。

1
2
3
4
5
6
7
8
9
def mask2addr(mask){
  mask = (-1 << (32-mask))
  (3..0).collect{(mask >> it*8) & 0xff}.join('.')
}


assert mask2addr(24)=="255.255.255.0"
assert mask2addr(25)=="255.255.255.128"
assert mask2addr(32)=="255.255.255.255"


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Option Explicit

' 与えられた数値を二進数に変換したときの1の数をカウントして返却する
Function countBinaryBits(num)
    Dim result, currentNum

    result = 0
    currentNum = num
    While currentNum > 0
        result = result + (currentNum Mod 2)
        currentNum = Int(currentNum / 2)
    Wend

    countBinaryBits = result
End Function

' IPv4のネットマスクアドレスを受け取って、マスクビット数を返却する
Function IPv4NetMaskToBits(strIpv4NetMask)
    Dim result, strIpv4NetMaskList, netMask

    result = 0
    strIpv4NetMaskList = Split(strIpv4NetMask, ".")
    For Each netMask In strIpv4NetMaskList
        result = result + countBinaryBits(CInt(netMask))
    Next

    IPv4NetMaskToBits = result
End Function

' マスク数を2進数に変換
Function getMaskFromBits(bits)
    Dim result, currentBits, i

    result = 0
    currentBits = bits
    For i = 7 to 0 Step - 1
        If currentBits > 0 Then
            result = result + 2 ^ i
            currentBits = currentBits - 1
        End If
    Next

    getMaskFromBits = result
End Function

' マスクビット数を受け取って、IPv4のネットマスクアドレスを返却する
Function bitsToIPv4NetMask(bits)
    Dim currentBits
    Dim result
    Dim i

    currentBits = bits
    result = ""
    For i = 1 to 4
        If result <> "" Then
            result = result & "."
        End If

        If currentBits >= 8 Then
            result = result & CStr(getMaskFromBits(8))
            currentBits = currentBits - 8
        ElseIf currentBits > 0 Then
            result = result & CStr(getMaskFromBits(currentBits))
            currentBits = 0
        Else
            result = result & "0"
        End If
    Next

    bitsToIPv4NetMask = result
End Function

msgbox IPv4NetMaskToBits("255.255.255.0")
msgbox IPv4NetMaskToBits("255.255.255.128")
msgbox IPv4NetMaskToBits("255.255.255.255")

msgbox bitsToIPv4NetMask(24)
msgbox bitsToIPv4NetMask(25)
msgbox bitsToIPv4NetMask(32)

Lost_dogです。

wordsByとsplitsAtは自分のユーティリティから引っ張ってきました。あると便利です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import Numeric
import Data.List

ipMaskToInt = length.takeWhile (=='1').(>>= f).wordsBy (=='.')
  where f xs = showIntAtBase 2 ("01"!!) (read xs) ""

intToIpMask x = intercalate "." $ map f $ splitsAt 8 $ ([1..x]>>"1")++([1..32-x]>>"0")
  where f = show.fst.head.readInt 2 (`elem`"01") (read.(:[]))

wordsBy p [] = []
wordsBy p xs = ys : wordsBy p (drop 1 zs) where (ys,zs) = break p xs

splitsAt n [] = []
splitsAt n xs = ys : splitsAt n zs where (ys,zs) = splitAt n xs

もっと美しく書ける気がします。
これが今の僕の限界です orz
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace Doukakuorg

open System
open System.Text.RegularExpressions

type C253 public () =
    member this.MaskToBit ip =
        if Regex.IsMatch(ip, @"^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$") then
            ip.Split('.')
                |> Array.map (fun a -> Convert.ToInt32(a))
                |> Array.map (fun a -> Convert.ToString(a, 2))
                |> Array.fold (fun s n -> s + n) ""
                |> (fun a -> a.Replace("0", "").Length)
        else
            0

    member this.BitToMask bit =
        if 1 <= bit && bit <= 32 then
            (new String('1', bit)).PadRight(32, '0')
                |> (fun a -> [for i in 0..8..(a.Length-1) do yield a.[i .. (i+7)]])
                |> List.map (fun a -> Convert.ToInt32(a, 2))
                |> List.fold (fun s n -> String.Format("{0}.{1}", s, n)) ""
                |> (fun a -> a.[1..])
        else
            "0.0.0.0"

Index

Feed

Other

Link

Pathtraq

loading...