Я в твоїх підмережах, граючи твій код


17

Виклик

Враховуючи IPv4 addressу крапкових чотирьох позначеннях та IPv4 subnetу позначеннях CIDR , визначте, чи addressє значення у subnet. Виведіть чітке і послідовне значення, якщо воно знаходиться в subnet, і окреме чітке і послідовне значення, якщо воно не в subnet. Вихідні значення не обов'язково повинні бути truthy / falsey у вашій мові.

Короткий праймер позначення підмережі CIDR

Мережеві адреси IPv4 мають довжину 32 біти, розділені на чотири групи з 8 біт для зручності читання. Позначення підмережі CIDR - це маска заданої кількості бітів, починаючи з лівого лівого краю. Наприклад, для /24підмережі це означає, що в цій підмережі доступні найчастіше 8 біт адреси. Таким чином, дві адреси, які розділені максимум 255і мають однакову маску підмережі, знаходяться в одній підмережі. Зауважте, що для дійсного CIDR всі хости (бік праворуч) зняті (нулі).

xxxxxxxx xxxxxxxx xxxxxxxx 00000000
^---    subnet mask   ---^ ^-hosts-^

В іншому прикладі /32підмережі вказано, що всі біти є маскою підмережі, по суті означає, що дозволений лише один хост на /32.

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
^---        subnet mask        ---^

Приклади:

Використання Trueдля "в підмережі" та False"не в підмережі" як вихід:

127.0.0.1
127.0.0.0/24
True

127.0.0.55
127.0.0.0/23
True

127.0.1.55
127.0.0.0/23
True

10.4.1.33
10.4.0.0/16
True

255.255.255.255
0.0.0.0/0
True

127.1.2.3
127.0.0.0/24
False

127.1.2.3
127.1.2.1/32
False

10.10.83.255
10.10.84.0/22
False

Правила та уточнення

  • Оскільки аналіз входу не є цікавим моментом цієї проблеми, ви гарантовано отримаєте дійсні адреси IPv4 та маски підмережі.
  • Введення та вихід можуть бути надані будь-яким зручним методом .
  • Ви можете роздрукувати результат в STDOUT або повернути його як результат функції. Будь ласка, вкажіть у своєму поданні, які значення може приймати результат.
  • Прийнятна або повна програма, або функція.
  • Стандартні лазівки заборонені.
  • Це тому діють усі звичайні правила гольфу, і найкоротший код (у байтах) виграє.

Чи потрібно брати дані в тому ж форматі, що і ваші тестові приклади?
Втілення

1
@EmbodimentofIgnorance Не потрібно сприймати їх як один за рядком, як у прикладах, але вам потрібно сприймати їх як пунктир з чотирма та пунктирними підмережами, як у прикладах. (наприклад, дивіться відповідь JavaScript від Arnauld)
AdmBorkBork

Чи добре їх розділяти косою рисою, наприклад 10.0.0.1/10.0.0.0”/16?
Нік Кеннеді

1
@ Poke Я погоджуюся, що ви правильні в тому, що позначення CIDR описують IP-адресу та розмір підмережі. Як і в, 1.255.1.1/8є дійсним виразом CIDR , що представляє хост 1.255.1.1всередині мережі 1.0.0.0з маскою підмережі 255.0.0.0. Однак виклик вимагає вказати номер мережі та підмережу конкретно в позначеннях CIDR, що 1.255.1.1/8не є дійсним номером мережі та комбінацією підмережі.
640

1
Тепер нам також потрібна версія IPv6 цього виклику
Феррібіг

Відповіді:


13

Python 3 (62 байти)

Дуже прямо:

from ipaddress import*
lambda i,m:ip_address(i)in ip_network(m)


3
Звичайно, у Mathematica є вбудована версія для всього - навіть для екзопланет ! Ніщо не може перемогти це ... Але, як ви могли переконатися, Python відповідає матчу козлового
формату

Цікаво, чи є ip_adressоб'єкт і ip_networkоб'єкт any convenient method, можливо, дозволяючи Python виграти, якщо тільки мова для гольфу на основі пітона не має таких типів?
мій займенник monicareinstate

Ви не отримаєте його в діапазоні 20 байт у звичайному Python. Тільки імпорт та лямбда вже довше відповіді Стакса. Це не дивно , що мови гольф виграти від «нормальних» мов ... :-(
agtoever

@someone: Я переміг Python з 53 байтами машинного коду x86-64 . :) Не є традиційною мовою для гольфу, і більшість розмірів коду аналізує string-> int вручну. (host^net)>>(32-mask)становить лише 10 байт. Але це на півдорозі для завдань, що не включають списки списків, або відображення функції в список, тому що багато скалярних операцій можна виконати з 2 або 3 байтовою інструкцією, а петлі можуть бути побудовані навколо речей у декілька байтів.
Пітер Кордес

4

C # (компілятор Visual C #) , 250 + 31 = 281 байт

(a,b)=>{Func<string,string>h=g=>string.Join("",g.Split('.').Select(x=>{var e=Convert.ToString(int.Parse(x),2);while(e.Length<8)e='0'+e;return e;}));a=h(a);var c=b.Split('/');b=h(c[0]);var d=int.Parse(c[1]);return a.Substring(0,d)==b.Substring(0,d);};

Рахунок включає using System;using System.Linq;

Спробуйте в Інтернеті!

Я написав це в JS, як тільки було опубліковано виклик, але Арнаулд бив мене на удар набагато кращою відповіддю, тож ось це на C #.

Однозначно багато місця для гольфу.

Пояснення:

Функція складається з підфункції, яка називається h:

h=g=>string.Join("",
    g.Split('.').Select(x => {
        var e = Convert.ToString(int.Parse(x), 2);
        while (e.Length < 8) e = '0' + e;
        return e;
    }
);

Ця підфункція розбиває IP-адресу увімкнено ., перетворює кожне число у двійкову рядок, ліву колодки -0 колодкою довжиною 8 біт, а потім об'єднує рядки в одну 32-бітну двійкову рядок.

Це негайно робиться на місці a=h(a);за вказаною IP-адресою.
Потім ми розділимо маску підмережі на IP-адресу та номер маски за допомогоюc=b.Split('/');

Компонент IP-адреси також передається через нашу підфункцію: b=h(c[0]); і номер маски аналізується на ціле число:var d=int.Parse(c[1]);

Нарешті ми беремо перші dбіти обох двійкових рядків (деd номер маски) і порівнюємо їх:return a.Substring(0,d)==b.Substring(0,d);


1
Занадто втомився, щоб це вирішити, тому я просто гольфував твої для тебе
Термін дії закінчився

1
Насправді забув про PadLeft в тому, що теж спробуйте в Інтернеті!
Термін дії якого минув

Багато оптимізацій. Я радий повідомити вам, що ваш rPad- це вбудований на рядках. пастербін посилання на TIO посилання, яке занадто довго поодинці
моя займенник monicareinstate

2
@someone Small FYI: Коротки URL-адрес, такі як tinyurl.com , дозволені в коментарях до цього SE, на відміну від більшості. :)
Кевін Круїссен

1
188 - tinyurl.com/y6xfkbxt - хороші поради URL вкорочення @KevinCruijssen
Dana

4

Оболонка Linux POSIX (з мережевими інструментами / iputils) (34 байти, які не закінчуються, 47 байт закінчується)

Що найкраще підходить для розбору мережевих масок та адрес, ніж самі мережеві утиліти? :)

route add -net $2 reject;! ping $1

Увага: сценарій потенційно може зашкодити вашому підключенню до Інтернету, будь ласка, працюйте обережно.

Вхід: сценарій приймає перевірену IP-адресу як перший аргумент, а тестовану підмережу. як другий аргумент.

Вихід: скрипт повертає істинне значення (0), якщо перший аргумент сценарію належить до підмережі, зазначеної у другому аргументі. В іншому випадку він ніколи не припиниться.

Припущення: сценарій повинен бути запущений як користувач root у чистому середовищі ( тобто адміністратором не встановлено жодного іншого маршруту чорного отвору. Якщо попередній екземпляр сценарію був запущений, створений створений ним маршрут видалено ). Сценарій також передбачає "робоче з'єднання з Інтернетом" ( тобто є дійсний маршрут за замовчуванням).


Пояснення:

Ми створюємо маршрут чорного отвору до вказаної підмережі. Потім ми перевіряємо підключення до наданої IP-адреси за допомогою ping . Якщо адреса не належить до підмережі (а оскільки ми припускаємо належне встановлення підключення до Інтернету), ping спробує надіслати пакети на цю адресу. Зауважте, що відповідь на цю адресу насправді не має значення, оскільки ping буде намагатися постійно. І навпаки, якщо адреса дійсно належить до підмережі, ping не вдасться за допомогою ENETUNREACH і поверне 2, і оскільки ми заперечили команду, сценарій буде успішним.


Приклад

Перевірте, чи належить 5.5.5.5 до 8.8.8.0/24

$ sudo ./a.sh 5.5.5.5 8.8.8.0/24
PING 5.5.5.5 (5.5.5.5) 56(84) bytes of data.
[...runs forever...]

(Очистити с sudo ip route del 8.8.8.0/24за допомогою команди після запуску команди).

Перевірте, чи належить 5.5.5.5 до 5.5.5.0/24:

$ sudo ./a.sh 5.5.5.5 5.5.5.0/24
connect: Network is unreachable
$ echo $?
0

(Очистити с sudo ip route del 5.5.5.0/24за допомогою команди після запуску команди).

Перевірте, чи належить 8.8.8.8 до 5.5.5.0/24:

$ sudo ./a.sh 8.8.8.8 5.5.5.0/24
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=122 time=2.27 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=122 time=1.95 ms
[...runs forever...]

(Очистити sudo ip route del 5.5.5.0/24за допомогою команди після запуску команди).


47-байтна версія, якщо ми забороняємо не припиняти сценарії

route add -net $2 reject;ping -c1 $1;[ $? = 2 ]

Відповідно до коментаря @ Grimy, ось версія, яка завжди закінчується, і повертає 0 (truthy), якщо адреса знаходиться в підмережі, а 1 (false). Ми робимо, що ping припиняється -c1прапором, який обмежує кількість відправлених пакетів до 1. Якщо відповідь на адресу, ping поверне 0, а якщо ні, то ping повернеться 1. Тільки якщо адреса належить до підмережі blackholed, ping повернеться 2, саме тому ми перевіряємо в останній команді.


3
Хоча розумно, це не відповідає вимозі виводити чітке і послідовне значення, якщо адреса відсутня в підмережі ( запущена вічно не вважається результатом , див. Також це ).
Grimmy

1
@Grimy: Але це мовчки не працює вічно, тому застосовується лише ваше 2-е посилання, не перше. Також я думаю, pingщо загинув би від SIGPIPE, якби він працював зі stdout + stderr, запровадженим в іншу програму, і читач закрив трубу. І це найімовірніший випадок використання, тому що статус виходу може бути успішним у будь-якому випадку (якщо ми додамо -c1можливість ping для встановлення підрахунку.) Але впевнений, читання його результатів з var=$(/a.sh)не вдасться; вам знадобиться читач, який зупинився після прийняття рішення, а не читати весь вихід і потім дивитися на нього.
Пітер Кордес

@Grimy Справедливий пункт (хоча заради аргументу я міг би сказати, що у нас є два послідовних значення, оскільки pingвони закінчуються менше ніж, скажімо, за одну секунду у випадку нестандартної адреси). Я додав завершальну версію для додаткових 13 байтів! :)
yoann


3

PHP , 101 92 88 байт

-13 байт від @gwaugh

function($i,$r){[$r,$n]=explode('/',$r);return(ip2long($i)&~(1<<32-$n)+1)==ip2long($r);}

Спробуйте в Інтернеті!


2
Повеселилися в гольф (Ty!):function($i,$r){return!((ip2long($i)^ip2long(strtok($r,'/')))>>32-strtok(_));}
Крістоф

@Christoph дуже приємно! Ніколи мені не спадало на думку, що ви можете просто використовувати будь-який маркер для другого дзвінка strtok(). Ваш на 4 байти коротший, ніж моя дуже схожа відповідь нижче. Реквізит!
640

@Christoph Ви повинні розмістити своє рішення як окрему відповідь, оскільки це краще, ніж моє.
Luis felipe De

3

PowerPC / PPC64 C, 116 114 байт

#include<stdio.h>
main(){unsigned u[4];char*p=u;for(;p<u+3;)scanf("%hhu%c",p++,u+3);return!((*u^u[1])>>32-p[-4]);}

(Тестовано на x86_64 Ubuntu 18.04 за допомогою powerpc64-linux-gnu-gcc -static та qemu-користувача.)

Програма приймає два рядки на стандартному вході, і в якості вихідного коду вона повертає 1, якщо адреса відповідає, і 0, якщо ні. (Отже, це залежить від специфікації, яка не вимагає значення трикутника для відповідності та значення фальси для невідповідності.) Зауважте, що якщо ви працюєте в інтерактивному режимі, вам потрібно буде подати сигнал EOF ( ^D) три рази після введення другого рядка.

Це покладається на те, що PowerPC є big-endian, а також на цій платформі, що повертає 0 для правого зміщення 32-бітового непідписаного значення на 32. Він зчитує октети на неподписані значення по одному, а також довжину сітки маски в іншому байті ; тоді він приймає xor двох непідписаних 32-бітних адрес і зміщує невідповідні біти. Нарешті, це стосується! для задоволення вимоги повернення лише двох різних значень.

Примітка. Можливо, можливо, відточити два байти заміною u+3наp і вимагає компіляції з -O0. Хоча жити небезпечніше, ніж я дбаю.

Дякую Пітеру Кордесу за натхнення для цього рішення.


Більш портативний C, 186 171 167 байт

Тут я збережу більш портативну версію, яка працює на 167 байтах.

#include<stdio.h>
main(){unsigned a,b,c,d,e,f,g,h,n;scanf("%u.%u.%u.%u %u.%u.%u.%u/%u",&a,&b,&c,&d,&e,&f,&g,&h,&n);return!(n&&((((a^e)<<8|b^f)<<8|c^g)<<8|d^h)>>32-n);}

Ця програма приймає два рядки на стандартному вході та повертає код виходу 1, якщо адреса знаходиться в підмережі, і 0, якщо це не так. (Таким чином, це покладається на специфікацію, яка не вимагає трибунного значення для матчів і значення фальси для не збігів.)

Розбивка основного виразу:

  • a^e, b^f, c^g,d^h Обчислює виключає адреса і маску байт за байтом.
  • (((a^e)<<8|b^f)<<8|c^g)<<8|d^h потім об'єднує їх в єдине непідписане 32-бітове значення методом Горнера.
  • ...>>32-n потім зміщує біти різниці xor, які не мають відношення до маски підмережі (маючи на увазі, що - в C більше пріоритет, ніж <<)
  • Хоча є одна готча: якщо n = 0, то це ~0U<<32призведе до невизначеної поведінки, вважаючи, що unsignedце 32 біти (що є практично на всіх поточних платформах). З іншого боку, якщо n = 0, то будь-яка адреса буде відповідати, значитьn&&... це дасть правильний результат (скориставшись поведінкою короткого замикання &&).
  • Нарешті, для задоволення вимоги, що вихід може бути лише одним із двох значень, ми застосовуємо !до виводу 0 або 1.

-15 байт через коментарі стельової кішки та AdmBorkBork

-4 байти через коментар Пітера Кордеса


1
Використання вихідних кодів для повернення значень є одним із методів вводу / виводу за замовчуванням і тому дозволено.
AdmBorkBork

@ceilingcat Звичайно, як нерозумно мені це пропустити.
Даніель

@AdmBorkBork Добре, спасибі, я змінив його, щоб використовувати вихідний код.
Даніель

Ідея: націліть реалізацію на C-маленький або великий-ендіан (код-гольф не потребує переносного коду) та введення покажчиків на вхідні кадри на байти unsigned. наприклад, з char*p=&aтодішнім p++,p++,p++,...або p--,...як аргументи scanf. Рядок формату повинен бути "%hhu.%hhu..."хоч і таким, що це суттєвий компроміс між цим додатковим розміром порівняно з оголошенням меншої кількості вар та можливістю зробити це(a^b)>>(32-count)
Пітер Кордес

1
@PeterCordes Так, правильна зміна працює, дякую.
Даніель

2

Стакс , 22 байти

é.○▄╗jF⌐§╥§I╓☻lw«ç┴║╫┼

Запустіть і налагоджуйте його

Він займає вхідні параметри, розділені простором на стандартному вході.

Розпакований, неозорений та прокоментований, це виглядає приблизно так.

'/:/~       split on slash and push the last group back to the input stack
j{          split on space; for each group, run this code block
  './       split on period
  {emVB|E   evaluate integers and decode integer as base-256
  ;e|<      peek from input stack and shift left
  Vu/       integer divide by 2^32
F           end of for-each
=           two values left on stack are equal?

Виконати цей


2

функція машинного коду x86-64, 53 48 байт

журнал змін:

  • -2 jz за зміну замість використання 64-бітового зсуву для обробки>>(32-0) спеціального випадку.
  • -3 повернення в ZF замість AL, економлячи 3 байти за a setnz al .

(Дивіться також відповідь 32-розрядного машинного коду Даніеля Шеплера на , який потім розвивався, щоб використовувати деякі інші ідеї, які ми мали. Я включаю останню версію цього внизу цієї відповіді.)


Повертає ZF = 0 для хоста немає в підмережі, ZF = 1 для в підмережі, тому ви можете розгалужувати результат за допомогоюje host_matches_subnet

Телефонується за допомогою системи V86 x86-64, яка називає конвенцію як
bool not_in_subnet(int dummy_rdi, const char *input_rsi); якщо б ви додалиsetnz al .

Рядок введення містить як хост, так і мережу, розділені рівно одним нецифровим символом. Пам'ять після кінця ширини CIDR повинна містити щонайменше 3 нецифрових байти до кінця сторінки. (У більшості випадків це не повинно бути проблемою, як, наприклад, аргумент cmdline.) У 32-розрядної версії Даніеля немає цього обмеження.

Ми виконуємо один і той же цикл крапкового синтаксичного розбору 3 рази, отримуючи дві адреси IPv4 і отримуючи /maskціле число у високому байті dword. (Ось чому після пам'яті має бути читабельна пам'ять /mask, але не має значення, чи є цифри ASCII.)

Ми робимо, (host ^ subnet) >> (32-mask)щоб витіснити біти хоста (ті, яким дозволено невідповідність), залишаючи лише різницю між підмережею і хостом. Щоб вирішити /0особливий випадок, коли нам потрібно зрушити на 32, переходимо через зсув на count = 0. ( neg clвстановлює ZF, на який ми можемо розгалужуватися і залишати як повернене значення, якщо ми не зміщуємо.) Зауважте, що 32-mask mod 32 = -maskі скалярні зсуви x86 маскують їх кількість на & 31або & 63.

    line  addr   machine                NASM source.  (from nasm -felf64 -l/dev/stdout)
    num          code bytes

     1                             %use smartalign
     2                             
     3                                 ;10.4.1.33 10.4.0.0/23         true
     4                                 ;10.4.1.33 10.4.0.0/24         false
     5                             
     6                             ;; /codegolf/185005/im-in-your-subnets-golfing-your-code
     7                             %ifidn __OUTPUT_FORMAT__, elf64
     8                             in_subnet:
     9                             
    10 00000000 6A03                   push 3
    11 00000002 5F                     pop  rdi                    ; edi = 3 dotted-quads to parse, sort of.
    12                             .parseloop:
    13                             
    14                                 ;xor  ebx,ebx             ; doesn't need to be zeroed first; we end up shifting out the original contents
    15                                 ;lea  ecx, [rbx+4]
    16 00000003 6A04                   push   4
    17 00000005 59                     pop    rcx                  ; rcx = 4 integers in a dotted-quad
    18                             .quadloop:
    19                             
    20 00000006 31D2                   xor   edx,edx               ; standard edx=atoi(rdi) loop terminated by a non-digit char
    21 00000008 EB05                   jmp  .digit_entry
    22                              .digitloop:
    23 0000000A 6BD20A                 imul   edx, 10
    24 0000000D 00C2                   add    dl, al
    25                              .digit_entry:
    26 0000000F AC                     lodsb
    27 00000010 2C30                   sub    al, '0'
    28 00000012 3C09                   cmp    al, 9
    29 00000014 76F4                   jbe   .digitloop
    30                                 ; al=non-digit character - '0'
    31                                 ; RDI pointing to the next character.
    32                                 ; EDX = integer
    33                             
    34 00000016 C1E308                 shl    ebx, 8
    35 00000019 88D3                   mov    bl, dl               ; build a quad 1 byte at a time, ending with the lowest byte
    36 0000001B E2E9                   loop .quadloop
    37                             
    38 0000001D 53                     push   rbx          ; push result to be collected after parsing 3 times
    39 0000001E FFCF                   dec    edi
    40 00000020 75E1                   jnz   .parseloop
    41                             
    42 00000022 59                     pop    rcx   ; /mask  (at the top of a dword)
    43 00000023 5A                     pop    rdx   ; subnet
    44 00000024 58                     pop    rax   ; host
    45 00000025 0FC9                   bswap  ecx   ; cl=network bits  (reusing the quad parse loop left it in the high byte)

    49 00000027 F6D9                   neg    cl
    50 00000029 7404                   jz   .all_net     ; skip the count=32 special case
    51                             
    52 0000002B 31D0                   xor    eax, edx   ; host ^ subnet
    53 0000002D D3E8                   shr    eax, cl    ; shift out the host bits, keeping only the diff of subnet bits
    54                             
    55                             .all_net:
    56                                ; setnz  al         ; return ZF=1 match,  ZF=0 not in subnet
    57 0000002F C3                     ret
    58 00000030 30                 .size:      db $ - in_subnet

              0x30 = 48 bytes

(не оновлюється останньою версією) Спробуйте в Інтернеті!

у тому числі, _startщо викликає його argv[1]і повертає статус виходу.

## on my desktop
$ ./ipv4-subnet "10.4.1.33 10.4.0.0/24"    && echo "$? : in subnet" || echo "$? : not in subnet"
not in subnet

$ ./ipv4-subnet "10.4.1.33 10.4.0.0/23"    && echo "$? : in subnet" || echo "$? : not in subnet"
in subnet

Це добре працює, якщо ви передаєте аргумент командного рядка, що містить новий рядок, а не пробіл. Але це має бути замість цього , не дуже.


32-бітна функція машинного коду x86, 38 байт

Зробіть 9 цілочисельних -> uint8_t розбирає і "натискаємо" їх на стек, де ми вискакуємо їх як dwords або використовуємо останній ще в CL. Уникайте взагалі читання минулого кінця рядка.

Крім того, decу 32-бітному режимі є лише 1 байт.

    72                             in_subnet:
    73 00000000 89E7                   mov   edi, esp
    74 00000002 51                     push  ecx
    75 00000003 51                     push  ecx                   ; sub esp,8
    76                             .byteloop:
    77                             
    78 00000004 31C9                   xor   ecx,ecx               ; standard ecx=atoi(rdi) loop terminated by a non-digit char
    79                                                             ; runs 9 times: 8 in two dotted-quads, 1 mask length
    80 00000006 EB05                   jmp  .digit_entry
    81                              .digitloop:
    82 00000008 6BC90A                 imul   ecx, 10
    83 0000000B 00C1                   add    cl, al
    84                              .digit_entry:
    85 0000000D AC                     lodsb
    86 0000000E 2C30                   sub    al, '0'
    87 00000010 3C09                   cmp    al, 9
    88 00000012 76F4                   jbe   .digitloop
    89                                 ; RDI pointing to the next character.
    90                                 ; EDX = integer
    91                             
    92 00000014 4F                     dec    edi
    93 00000015 880F                   mov    [edi], cl           ; /mask store goes below ESP but we don't reload it
    94 00000017 39E7                   cmp    edi, esp
    95 00000019 73E9                   jae   .byteloop
    96                             
    97                                 ;; CL = /mask still there from the last conversion
    98                                 ;; ESP pointing at subnet and host on the stack, EDI = ESP-1
    99                             
   100 0000001B 5A                     pop    edx   ; subnet
   101 0000001C 58                     pop    eax   ; host
   102                             
   103 0000001D 31D0                   xor    eax, edx             ; host ^ subnet
   104 0000001F F6D9                   neg    cl                   ; -mask = (32-mask) mod 32;  x86 shifts mask their count
   105 00000021 7402                   jz     .end                 ; 32-n = 32 special case
   106 00000023 D3E8                   shr    eax, cl
   107                             .end:
   108                                 ; setz  al                  ; just return in ZF
   109 00000025 C3                     ret

   110 00000026 26                 .size:      db $ - in_subnet
      0x26 = 38 bytes

Тестуючий абонент

   113                             global _start
   114                             _start:
   115 00000027 8B742408               mov    esi, [esp+8]   ; argv[1]
   116 0000002B E8D0FFFFFF             call   in_subnet
   117 00000030 0F95C3                 setnz  bl
   118 00000033 B801000000             mov    eax, 1         ; _exit syscall
   119 00000038 CD80                   int    0x80

Мені цікаво, як пройде 32-розрядний байт ASM, якби замість того, cmp/jccщо ви згадали, ви робили щось на кшталт xor edx,edx;neg cl;cmovz eax,edx;shr eax,cl- або, можливо, у вас вже є десь значення, що висить. (І тоді вам не знадобиться sub cl,32інструкція.)
Даніель

1
Так, схоже, що ediповинно бути 0, коли цикл закінчується, так і xor eax,edx;neg cl;cmovz eax,edi;shr eax,clмає працювати.
Даніель

1
Якщо я порахував речі правильно, cmove eax,ediмає 3 байти, що є миттям над видаленими, sub cl,32то shr cl,eaxзберігає один байт shr cl,raxі 32-бітний dec ediзберігає один байт над 64-бітовим dec edi. Потім моя збірка дає .byte 0x33(у синтаксисі бінутів GNU) = 51 для in_subnet.size.
Даніель

Гарна ідея, дякую. (У синтаксисі Intel це shr eax,cl, порівняно shr %cl, %eaxз синтаксисом AT&T, ваш останній коментар відмінив це.) Оновити відповіді на машинний код (і перенести _startабонента, який перекликає або повторно описати умову виклику для 32-бітного режиму). .), тож я може не обійтись. Сьогодні відчуваєш себе лінь. >. <
Пітер Кордес

1
Я щойно спробував реалізувати коментар, який ви поставили до моєї відповіді про позбавлення подвійного циклу і замість цього зберігання змінних стеків - і навіть із додатковим кодом для ініціалізації вказівника запису edi, написання виводу тощо. Це в кінцевому підсумку зберегло 2 байти в чистій. (Принаймні одного разу я зрозумів, що push ecx;push ecx;push ecxвін коротший sub esp,12; і здавалося, що я миюсь, чи я попередньо додав ediта використовував, std;stosb;cldчи просто зберігав, використовуючи dec edi;mov [edi],al.
Даніель

1

Желе , 23 байти

ṣ”/ṣ€”.Vḅ⁹s2+Ø%BḊ€ḣ€ʋ/E

Спробуйте в Інтернеті!

Монадічне посилання, яке приймає адресу та підмережу, розділене косою рисою, і повертає 1 для істинного та 0 для помилкового.

Завдяки @gwaugh за вказівку на недолік в оригіналі - він не зміг забезпечити, щоб двійковий список був 32 довгим.



1

05AB1E , 21 байт

'/¡`U‚ε'.¡b8jð0:JX£}Ë

Займає підмережу перед адресою.

Спробуйте в Інтернеті або перевірте всі тестові випадки .

Пояснення:

'/¡              '# Split the first subnet-input by "/"
   `              # Push both values separated to the stack
    U             # Pop and store the trailing number in variable `X`
                 # Pair the subnet-IP with the second address-input
     ε            # Map both to:
      '.¡        '#  Split on "."
         b        #  Convert each integer to binary
          8j      #  Add leading spaces to make them size 8
          ð0:     #  And replace those spaces with "0"
             J    #  Join the four parts together to a single string
              X£  #  And only leave the first `X` binary digits as substring
                # After the map: check if both mapped values are the same
                  # (which is output implicitly as result)

1

R 120 байт

функція - Я вставив ".32" на перший термін

w=function(a,b){f=function(x)as.double(el(strsplit(x,"[./]")));t=f(paste0(a,".32"))-f(b);sum(t[-5]*c(256^(3:0)))<2^t[5]}

і просто для розваги:

require("iptools");w=function(a,b)ips_in_cidrs(a,b)[[2]]

що становить 56 байт


1

PHP ,75 73, 71 байт

<?=strtok($argv[2],'/')==long2ip(ip2long($argv[1])&1+~1<<32-strtok(_));

Розділка на відповідь @Luis felipe De jesus Munoz , як окремий, який приймає дані з аргументів командного рядка. Виходи '1'для Truthy, ''(порожня рядок) для Fasley.

$ php ipsn.php 127.0.0.1 127.0.0.0/24
1
$ php ipsn.php 127.1.2.3 127.0.0.0/24

Спробуйте в Інтернеті!

-2 байт запозичення маленький трюк @Christoph для strtok(). Його відповідь все ж коротша!


1

x86 функція складання, 49 43 байти

Це в основному розміщено для задоволення запиту Пітера Кордеса щодо оновленої версії, яку я створив. Можливо, він може піти один раз / якщо він включить це у свою відповідь.

Ця функція очікує esiвказівки на рядок введення, з частинами адреси та підмережі, розділеними або пробілом, або символом нової лінії, а значення повернення - у прапорі ZF (який за визначенням має лише два можливі значення).

 1                                  %use smartalign
 2                                  
 3                                      ;10.4.1.33 10.4.0.0/23         true
 4                                      ;10.4.1.33 10.4.0.0/24         false
 5                                  
 6                                  ;; /codegolf/185005/im-in-your-subnets-golfing-your-code
 7                                  in_subnet:
 8                                  
 9                                      ;xor  ebx,ebx             ; doesn't need to be zeroed first; we end up shifting out the original contents
10                                      ;lea  ecx, [rbx+4]
11 00000000 6A09                        push   9
12 00000002 59                          pop    ecx                  ; ecx = 9 integers (8 in two dotted-quads,
13                                                                  ; 1 mask length)
14                                  
15 00000003 89E7                        mov   edi, esp
16 00000005 83EC0C                      sub   esp, 12
17                                  .quadloop:
18                                  
19 00000008 31D2                        xor   edx,edx               ; standard edx=atoi(rdi) loop terminated by a non-digit char
20 0000000A EB05                        jmp  .digit_entry
21                                   .digitloop:
22 0000000C 6BD20A                      imul   edx, 10
23 0000000F 00C2                        add    dl, al
24                                   .digit_entry:
25 00000011 AC                          lodsb
26 00000012 2C30                        sub    al, '0'
27 00000014 3C09                        cmp    al, 9
28 00000016 76F4                        jbe   .digitloop
29                                      ; al=non-digit character - '0'
30                                      ; RDI pointing to the next character.
31                                      ; EDX = integer
32                                  
33 00000018 4F                          dec    edi
34 00000019 8817                        mov    [edi], dl
35 0000001B E2EB                        loop .quadloop
36                                  
37 0000001D 59                          pop    ecx   ; /mask  (at the top of a dword)
38 0000001E 5A                          pop    edx   ; subnet
39 0000001F 58                          pop    eax   ; host
40 00000020 0FC9                        bswap  ecx   ; cl=network bits  (reusing the quad parse loop left it in the high byte)
41                                  
42                                  ;    xor    cl, -32    ; I think there's some trick like this for 32-n or 31-n, but maybe only if we're masking to &31?  Then neg or not work.
43                                  
44 00000022 31D0                        xor    eax, edx   ; host ^ subnet
45                                  ;    xor    edx, edx   ; edx = 0
46 00000024 F6D9                        neg    cl
47 00000026 7402                        jz     .end
48 00000028 D3E8                        shr    eax, cl    ; count=32 special case isn't special for a 64-bit shift
49                                  .end:    
50 0000002A C3                          ret
51 0000002B 2B                      .size:      db $ - in_subnet

І частина обгортки Linux x86:

53                                  global _start
54                                  _start:
55 0000002C 8B742408                    mov    esi, [esp+8]   ; argv[1]
56 00000030 E8CBFFFFFF                  call   in_subnet
57 00000035 0F95C0                      setnz  al
58 00000038 0FB6D8                      movzx  ebx, al
59 0000003B B801000000                  mov    eax, 1         ; _exit syscall
60 00000040 CD80                        int    0x80

-6 байт через пропозицію Пітера Кордеса повернути значення в ZF.


Я думаю, я міг би зберегти один байт, видаливши останній xor edx,edxі замінивши cmovz eax,edxна jz .nonzero; xor eax,eax; .nonzero:. cmovzвсе ще виграє, якщо у нас є конвенція про закликання ebx=0.
Даніель

Може , ми просто jzнад shrдо СЕТЗУ або в відставку? Ми можемо поміняти setnzна setzта повернутись 1на матч, якщо це допоможе. Або навіть сказати, що наша повернена вартість - ZF. Я мав би це зробити у своїй відповіді. (Але я не думаю, що ми можемо обґрунтувати, що вимагає, щоб абонент створив для нас константи, наприклад ebx=0. Моя відповідь на тему " Поради щодо гольфу в машинному коді x86 / x64" стверджує, що занадто далеко буде розтягнути спеціальну конвенцію про виклики.
Пітер Кордес

До речі, я використовую , cutщоб видалити деякі стовпці з лістингу виведення NASM , тому що всі мої інструкції короткі: nasm -felf foo.asm -l/dev/stdout | cut -b -34,$((34+6))-. Крім того, я використовував mov замість movzx у своєму _startвиклику, оскільки статус виходу походить від низького байта arg до sys_exit(). Ядро ігнорує більш високі байти.
Пітер Кордес

Я думаю, це спрацювало б. Це бере відлік до 43 байт , а потім вставити setnz alпісля call in_subnetв обгортці.
Даніель

Так. Легко уявити, що звичайним випадком використання цієї функції буде call/ je, а не друк або подальший результат у результаті. Як я зазначав у «підказках», деякі конвенції про виклики системних викликів уже роблять це в реальному житті (як правило, з CF = помилка).
Пітер Кордес

1

Java 215 211 207 202 200 199 198 198 180 180 байт

Long k,c;boolean a(String i,String s){return(b(i)^b(s))>>32-k.decode(s.split("/")[1])==0;}long b(String i){for(c=k=0l;c<4;k+=k.decode(i.split("[./]")[3+(int)-c])<<8*c++);return k;}

Вихідні дані trueдля правди і falseдля помилки .

Примітка. Це використовує longзамість intпотенційного зсуву 32.

Спробуйте в Інтернеті!

Збережено 1 байт завдяки плафоні

Збережено 10 байт завдяки Пітеру Кордесу


Це не дає "чіткого і послідовного значення" для фальси.
AdmBorkBork

Я б стверджував, що це чітко і послідовно не нульове значення, але якщо це не дух виклику, я можу це змінити.
Poke

64-бітове ціле число підтримує ліві зсуви на 32. Крім того, ви можете зрушити праворуч,host ^ net щоб змістити біти, які ви хочете видалити, а не створювати маску. Але я думаю, що Java потребує порівняння, щоб створити булеве значення з цілого числа. Можливо !, бо це не має значення, чи правда чи помилка ви виробляєте для якого виводу. (Я попросив ОП роз'яснити, чи мають намір виключити 0 / не нульове значення. Вони сказали, що так, що вони знають про наслідки цього формулювання:
Пітер Кордес

1
@PeterCordes Перетворення всього, longщо втрачає, втрачає мені кілька байтів, але я компенсую це тим, що можу видалити тернар і виконувати XOR, як ви пропонуєте. Я перевіряю, що ще можу
Poke

1

Вугілля деревне , 36 байт

≔⪪S/θ≔I⊟θζ⊞θSUMθ÷↨I⪪ι.²⁵⁶X²⁻³²ζ⁼⊟θ⊟θ

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Приймає підмережу як перший параметр і виводить -лише в тому випадку, якщо адреса лежить в межах підмережі. Пояснення:

≔⪪S/θ

Розділити підмережу на /.

≔I⊟θζ

Вийміть маску і киньте її на ціле число.

⊞θS

Натисніть адресу до масиву.

UMθ÷↨I⪪ι.²⁵⁶X²⁻³²ζ

Розбийте обидві адреси на ., перетворіть їх на цілі числа, інтерпретуйте як базові 256 та відкиньте замасковані біти.

⁼⊟θ⊟θ

Порівняйте два значення.


1

Japt , 26 байт

Ëq'/
ËÎq. Ë°¤ù8ì¯Ug1,1Ãr¶

Спробуй це

-3 байти завдяки @Shaggy!

Вхід - це масив з 2-х елементів [address, subnet]. Транспільований JS нижче:

// U: implicit input array
// split elements in U on the / and
// save back to U using a map function
U = U.m(function(D, E, F) {
  return D.q("/")
});
// map the result of the previous operation
// through another function
U.m(function(D, E, F) {
  return D
    // get the address portion of the / split
    // value and split again on .
    .g().q(".")
    // map each octet through another function
    .m(function(D, E, F) {
      // convert the octet to a base 2 string
      // left padded to a length of 8
      return (D++).s(2).ù(8)
    })
    // join the base 2 octets
    .q()
    // take the left bits of the joined octets
    // determined by subnet size
    .s(0, U.g(1, 1))
})
  // at this point, the intermediate result
  // contains 2 masked values, reduce
  // using === to check for equality
  .r("===")


Цікаво - я не розумів, що ви можете примусити рядок до числа ++.
Dana

Так, як можна в JS. Це, однак, не має сенсу, якщо вам потрібно згодом повторно використовувати початкове значення, але це зручно в деяких випадках.
Кошлатий

Потреба в комах у gметоді мене дратує; взагалі не можу розібратися. Принаймні, не той, який врятує вам байт.
Кошлатий


0

C # (Visual C # Interactive Compiler) , 134 байти

a=>a.Select(x=>x.Split('.','/').Take(4).Aggregate(0L,(y,z)=>y<<8|int.Parse(z))>>32-int.Parse(a[1].Split('/')[1])).Distinct().Count()<2

Спробуйте в Інтернеті!

Оператор LINQ, який приймає 2-елементний рядковий рядок як вхідний в [address, subnet] форматі.

Кожен пунктирний квадратик перетворюється на 32 біти довгими за допомогою маніпуляції бітом. Біти зміщуються вправо на розмір підмережі, а елементи порівнюються для рівності.

У той час, коли ця відповідь була розміщена, було кілька відповідей на C #, але жоден, який використовував чисту бітну маніпуляцію.

// a: input array containing address and subnet
a=>a
  // iterate over input elements
  .Select(x=>x
    // split element on . and /
    .Split('.','/')
    // the subnet will have 5 elements,
    // we only want the parts before the /
    .Take(4)
    // use an aggregate function to convert dotted quad to 32 bits
    .Aggregate(0L,(y,z)=>y<<8|int.Parse(z))
    // shift bits of aggregate to the right
    >>
    // shift amount determined by subnet size
    32-int.Parse(a[1].Split('/')[1])
  )
  // test for equality by checking if number
  // of unique values is equal to 1
  .Distinct()
  .Count()<2

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.