1. Куча / Говнокод #13663

    +116

    1. 1
    string pattern = @"\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?";

    Регулярка для IP //_*)

    Запостил: kegdan, 25 Августа 2013

    Комментарии (57) RSS

    • 999.999.999.999
      Ответить
      • Кстати, в uplink не играли? Там как раз числа в айпишках идут до 999 ;)
        Ответить
    • Что-то типа такого пиздеца:
      @"((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])"
      А вообще, регуляркой проверять адреса это моветон, так как обычно в какой-нибудь изкоробочной либе есть кошерный парсер, понимающий и ipv4 и ipv6.
      Ответить
      • Ну можно сократить немного...
        @"((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(?=\d)|$)){4}"
        Но солидарен со второй частью сообщения. :)
        Ответить
        • >> /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(\.(?=\d)|$)){4}/.test('127.0.0.1.1')
          > true

          у того петушка хотя бы работает
          Ответить
    • FILTER_VALIDATE_IP Спешит на помощь.
      Ответить
    • Ну учитывая #13458, регулярка требует серьезной доработки :)
      Ответить
      • Вообще для таких случаев, имхо, уже нужны грамматики, а не регулярки...
        Ответить
      • Доработал ;)
        ((0x([0-9a-f]|[1-9a-f][0-9a-f]{1,6}|[1-9a-f][0-9a-f]{7}))|([0-9]|[1-9][0-9]{1,8
        }|[1-3][0-9]{9}|4[0-1][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{
        5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[0-1][0-9]{2}|42949672[0-8][0-
        9]|429496729[0-5])|(0([0-7]|[1-7][0-7]{1,9}|[1-3][0-7]{10})))|((0x([0-9a-f]|[1-
        9a-f][0-9a-f]))|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(0([0-7]|[1-7]
        [0-7]|[1-3][0-7]{2})))\.(((0x([0-9a-f]|[1-9a-f][0-9a-f]{1,4}|[1-9a-f][0-9a-f]{5
        }))|([0-9]|[1-9][0-9]{1,6}|1[0-5][0-9]{6}|16[0-6][0-9]{5}|167[0-6][0-9]{4}|1677
        [0-6][0-9]{3}|16777[0-1][0-9]{2}|1677720[0-9]|1677721[0-5])|(0([0-7]|[1-7][0-7]
        {1,6}|[1-7][0-7]{7})))|((0x([0-9a-f]|[1-9a-f][0-9a-f]))|([0-9]|[1-9][0-9]|1[0-9
        ]{2}|2[0-4][0-9]|25[0-5])|(0([0-7]|[1-7][0-7]|[1-3][0-7]{2})))\.(((0x([0-9a-f]|
        [1-9a-f][0-9a-f]{1,2}|[1-9a-f][0-9a-f]{3}))|([0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4
        }|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])|(0([0-7]|[1-7][0-7]{1
        ,4}|1[0-7]{5})))|((0x([0-9a-f]|[1-9a-f][0-9a-f]))|([0-9]|[1-9][0-9]|1[0-9]{2}|2
        [0-4][0-9]|25[0-5])|(0([0-7]|[1-7][0-7]|[1-3][0-7]{2})))\.((0x([0-9a-f]|[1-9a-f
        ][0-9a-f]))|([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(0([0-7]|[1-7][0-7
        ]|[1-3][0-7]{2})))))
        http://ideone.com/fExEjm
        Ответить
        • Даже человек архиватор тут бессилен

          K6L7M8}|[1-3P9}|4[0-1P8}|42OB{7}|429[0-3P6}|4294OB{5}|42949[0-5P4}|429496[0-6P3}|4294967[0-1P2}|42949672OB|429496729N9}|[1-3]C{10}J(K4L5M6}|1[0-5P6}|16[0-6P5}|167[0-6P4}|1677[0-6P3}|1677[0-1P2}|1677720B|1677721N6}Q{7}J(K2L3M3}|[1-5P4}|6[0-4P3}|65[0-4P2}|655[0-2]B|6553N4}|1C{5}JH))

          A = [0-9a-f]
          B = [0-9]
          C = [0-7]
          D = [1-9a-f]
          E = A|DA
          F = [1-9]
          G = B|FB
          H =((0x(E))|(G|1B{2}|2[0-4]B|25[0-5])|(0(CQ|[1-3]C{2})))
          J = )))|H\.
          K = ((0x(E{1,
          L =}|DA{
          M = }))|(G{1,
          N = [0-5])|(0(CQ{1,
          O = [0-8]
          P = ]B{
          Q = |[1-7]C{
          Ответить
          • Хм. А человек архиватор нашел там 4 одинаковых фрагмента, отвечающих за диапазон 0..255? Или это и есть "H"?
            Ответить
        • (defpackage :ip-v4-grammar (:use :cl :esrap))
          
          (defrule digit (character-ranges (#\0 #\9)))
          
          (defrule octet (or (and #\2 (or (and #\5 (character-ranges (#\0 #\5)))
                                          (and (character-ranges (#\0 #\4)) digit)))
                             (and #\1 digit digit)
                             (and digit digit)
                             digit))
          
          (defrule ip-v4 (and octet #\. octet #\. octet #\. octet))
          
          (parse 'ip-v4 "127.0.0.1")
          Ответить
          • я конечно извиняюсь, но это на чем вообще написано?)
            Ответить
            • Common List же с макросами из esrap.
              Ответить
              • Кроме того, стоит заметить, что в отличие от регулярных выражений:
                - модульное (позволяет повторно использовать части выражений в других выражениях).
                - описывает больше грамматик.
                - конкретно в Лиспе можно дополнительно использовать любую функцию в качестве тест / лукахед / лукбихайнд.
                Ответить
                • >лукбихайнд
                  а классно было бы - язык программирования транслитом на русском...

                  деф фанкшен(листВан,листТу):
                  ____и = 0
                  ____вайл и<лен(листВан):

                  ну и тд
                  Ответить
                • Ну так это надо сравнивать с bison/parsec/spirit/antlr тогда, а не с регулярками ;)

                  При этом поди можно еще конвертировать строки в нужный формат на ходу, и на выхлопе parse получить готовое s-выражение, а не куски строк? :)
                  Ответить
                  • Не, генерировать не получится, оно работает как регулярные выражения: на вход строка, на выход совпадения / ошибка парсинга. AntLR / Parsec / Byson - это все LR(чего-нибудь) / LL(чего-нибудь) парсеры для регулярных грамматик, esrap - PEG, очень близко, но не то же самое.
                    Ответить
                  • Судя по всему, сливает парсеку
                    Ответить
          • Код рабочий, проверил.
            Ответить
        • Да ты упоротый.
          Ответить
          • Не бойся, я ненастолько упорот, чтобы писать это руками ;)

            P.S. Надо кому-нибудь генератор реджексов для проверки целочисленных интервалов аля [42..1500]?
            Ответить
            • Врядли нужно, но пости конечно. Хоть над говном посмеёмся.
              Ответить
              • > Хоть над говном посмеёмся.
                Это точно ;)

                http://govnokod.ru/13674
                Ответить
            • Случайно как то появился по рукой, ага?)
              Ответить
      • показать все, что скрытоОтсосу член парню из Владикавказа. Прут наглые хуястые самцы.

        [email protected] (Спросить Тараса)
        Ответить
    • А для ipv6 можно нагенерить.
      Ответить
    • Что, ТЕСТУХА?
      Ответить
    • В копилку самопальных парсеров. Самое короткое, что я смог написать.
      // returns 0 on success and 1 on parse error
      int parse_ipv4(const char *ipstr, unsigned char ip[4])
      {
          int b[] = {0, 0, 0, 0}, i = 0, r = 0;
          const size_t n = sizeof b / sizeof b[0];
          if (n != sscanf(ipstr, "%d.%d.%d.%d%n", &b[0], &b[1], &b[2], &b[3], &r)
      	|| r < 7 || 15 < r) {
      	return 1;
          }
          for (; i < n; ++i) {
      	if (b[i] < 0 || 255 < b[i]) {
      	    return 1;
      	}
      	ip[i] = (unsigned char)b[i];
          }
          return 0;
      }
      Ответить
      • Имхо, стоит !ipstr[r] поставить вместо 7 < r < 15, чтобы хлам в хвосте айпишника не принимался.
        Ответить
        • Да, я не уверен был, что sscanf нормально прожует переполнение int (т.к. переполнение uchar он молча проглатывал), поэтому предпочёл ограничение на длину. Лучше тогда так:
          ... || 15 < r || !ipstr[r]
          Ответить
      • Мой вариант (не тестил, может глючить):
        int parse_ipv4(const char *ipstr, unsigned char ip[4]) {
            for (int i=0; i<4; i++) {
                const char *p;
                int a = strtol(ipstr, &p, 10);
                if (a < 0 || a > 255 || p == ipstr || i<3 && *p != '.')
                     return 1;
                ipstr = p+1;
                ip[i] = a;
            }
            return !ipstr[0];
        }
        Ответить
        • да, так вроде лучше
          Ответить
          • Через полчасика до компа доберусь, исправлю пару досадных багов, закравшихся в код...
            Ответить
            • я надеялся одним sscanf-ом обойтись, думал коротко получится. Но коварное переполнение нарушило мои планы.
              Ответить
            • А на защеканном хачкеле?
              Ответить
              • import Text.ParserCombinators.Parsec
                import Control.Monad (mfilter)
                
                ok x = 0 <= x && x <= 255
                
                octet = mfilter ok (many1 digit >>= return . read)
                
                ipv4 =  mfilter ((== 4) . length) (octet `sepBy` (char '.'))
                
                parseIpv4 :: String -> Either ParseError [Int]
                parseIpv4 = parse ipv4 "(unknown)"
                Ответить
                • Сообщения об ошибке какие-то невменяемые.
                  "256.0.0.0": unexpected "." expecting digit.
                  "1.1.1.1.1": unexpected end of input expecting ".".

                  Не в курсе, как пофиксить?

                  P.S. Спасибо за прием с mfilter.
                  Ответить
                  • в плане сообщений об ошибках парсек упорот, я так и не смог заставить его выводить что-либо вменяемое при выходе из диапазона [0..255]
                    Ответить
                    • Попытался поразбираться с обработкой ошибок в парсеке..

                      ParseError содержит в себе пачку сообщений, каждое из которых может быть expected, unexpected и просто message. При конвертации в строку они объединяются в более-менее красивый вид, который мы видим в выхлопе.

                      <?> "some" генерит expected
                      unexpected "some" и satisfy f генерят unexpected
                      fail "some" генерит message

                      Зафейлившийся комбинатор <|>, как я понял, возвращает ParseError, в котором лежат все сообщения, которые вернули все его ветки. Т.е. если первая ветка ждала "x" но увидела "p", вторая ждала "y", но увидела "p", а третья вызвала fail "djihurda", то мы получим что-то в духе
                      unexpected p
                      expecting x or y
                      djigurda
                      Внутри sepBy и many1 как раз есть тот самый <|>...

                      P.S. Есть идейка как выправить вывод, попробую реализовать.
                      Ответить
                      • С удовольствием посмотрю на конечный результат. Вероятно, достаточно завелосипедить many1 и sepBy, чтобы они работали по-другому.
                        Ответить
                        • либо оставлять только последний Expected...
                          хотя нет, это врядли поможет.
                          Ответить
                          • Ну короче походу это полный фейл ;(

                            Все стандартные парсеры агрегируют ошибки, а доступа к кишкам, если я не туплю, нет, т.к. все конструкторы в привате.

                            Остается вот такой костыль, подламывающий вывод типов (приходится явно написать, что ipv4 это GenParser [Char] st [Int]):
                            check :: (a -> Bool) -> String -> a -> Either ParseError a
                            check f m x = if f x
                                then Right x
                                else Left (newErrorMessage (Message m) (initialPos ""))
                            
                            parseIpv4 s = parse ipv4 "" s >>=
                                check ((==4) . length) "IPv4 address must consists of 4 octets" >>=
                                check (all (<256)) "IPv4 octets must be less than 256"
                            P.S. На IdeOne парсека нет :(
                            P.P.S. Этот костыль, естественно, уже не выдает позицию, в которой случилась ошибка.
                            Ответить
      • Лайт версия (только 4 десятичных блока): http://ideone.com/q2GKqR
        /* returns 0 on success, 1 on parse error */
        int strtoipv4(const char *ipstr, unsigned char ip[4]) {
            for (int i=0; i<4; i++) {
                if (*ipstr < '0' || *ipstr > '9')
                    return 1;
                const char *p;
                unsigned long a = strtoul(ipstr, (char**)&p, 10);
                if (p == ipstr || a > 255 || (i < 3 && *p++ != '.'))
                    return 1;
                ip[i] = a;
                ipstr = p;
            }
            return !!*ipstr;
        }

        Фулл версия (все варианты ипв4 + возврат хвоста по аналогии с strtoul): http://ideone.com/eYccnC
        Ответить
    • http://0x57fafb03/ отсосите
      Ответить
      • Огромная регулярка из моего коммента схавает и такое ;)
        И даже 0127.0xFA.0xFB03
        Ответить
        • 0x123456789 она тоже схавает.
          Ответить
          • То есть, она пойдет разве что для отбора кандидатов на тестирование ipv4toint.
            Ответить
          • > 0x123456789 она тоже схавает.
            Не должна. Проверял?
            Ответить
            • В посте http://govnokod.ru/13663#comment192990 ты $ забыл.

              Дальше ковырять не буду, ибо говнокод полностью нечитаем.
              Ответить
              • Ну в ideone он добавлен был, равно как и ^.

                > ибо говнокод полностью нечитаем.
                Как и любая регулярка больше 20-30 символов...
                Ответить
                • Ну я не перехожу по каждому адресу, который даже не оформлен ссылкой.

                  Тут недавно пробегал свернутый регексп для проверки емейл адресов. Выглядел вполне цивильно.
                  Ответить
                  • Адрес был оформлен как ссылка. Хочется доебаться - так доябывайся к фактам, а не к своим фантазиям ;)
                    Ответить
    • и зачем тут вообще регулярки?
      Ответить

    Добавить комментарий