IPV6-адрес в сжатой форме на Java - PullRequest
13 голосов
/ 12 августа 2011

Я использовал Inet6Address.getByName("2001:db8:0:0:0:0:2:1").toString() метод для сжатия адреса IPv6, и вывод 2001:db8:0:0:0:0:2:1, но мне нужно 2001:db8::2:1., Как правило, выходные данные сжатия должны основываться на стандарте RFC 5952 , то есть

1) Сокращаться настолько, насколько это возможно : например, 2001: db8: 0: 0: 0: 0: 2: 1 должно быть сокращено до
2001: db8 :: 2: 1. Аналогично, 2001: db8 :: 0: 1 недопустимо, поскольку символ "::msgstr "можно было бы использовать для создания более короткого представления 2001: db8 :: 1.

2) Обработка одного 16-битного поля 0 : Символ "::" НЕ ДОЛЖЕН использоваться для сокращения только одного 16-битного поля 0.Например, представление 2001: db8: 0: 1: 1: 1: 1: 1 является правильным, но 2001: db8 :: 1: 1: 1: 1: 1 не является правильным.

3) Выбор в расположении "::" : = Когда есть альтернативный выбор в расположении "::", самый длинный цикл последовательных 16-битовых полей 0 ДОЛЖЕН бытьукороченный (т. е. последовательность с тремя последовательными нулевыми полями в 2001 году сокращается: 0: 0: 1: 0: 0: 0: 1).Когда длина последовательных 16-битовых 0 полей равна (т. Е. 2001: db8: 0: 0: 1: 0: 0: 1), первая последовательность нулевых битов ДОЛЖНА быть сокращена.Например, 2001: db8 :: 1: 0: 0: 1 - правильное представление.

Я также проверил другой пост в переполнении стека , но былусловие не указано (пример выбора при размещении: :).

Есть ли какая-нибудь библиотека Java для этого?Может ли кто-нибудь помочь мне?

Заранее спасибо.

Ответы [ 6 ]

19 голосов
/ 12 августа 2011

Как насчет этого?

String resultString = subjectString.replaceAll("((?::0\\b){2,}):?(?!\\S*\\b\\1:0\\b)(\\S*)", "::$2");

Объяснение без Java двойной обратной косой черты:

(       # Match and capture in backreference 1:
 (?:    #  Match this group:
  :0    #  :0
  \b    #  word boundary
 ){2,}  # twice or more
)       # End of capturing group 1
:?      # Match a : if present (not at the end of the address)
(?!     # Now assert that we can't match the following here:
 \S*    #  Any non-space character sequence
 \b     #  word boundary
 \1     #  the previous match
 :0     #  followed by another :0
 \b     #  word boundary
)       # End of lookahead. This ensures that there is not a longer
        # sequence of ":0"s in this address.
(\S*)   # Capture the rest of the address in backreference 2.
        # This is necessary to jump over any sequences of ":0"s
        # that are of the same length as the first one.

Ввод:

2001:db8:0:0:0:0:2:1
2001:db8:0:1:1:1:1:1
2001:0:0:1:0:0:0:1
2001:db8:0:0:1:0:0:1
2001:db8:0:0:1:0:0:0

Вывод:

2001:db8::2:1
2001:db8:0:1:1:1:1:1
2001:0:0:1::1
2001:db8::1:0:0:1
2001:db8:0:0:1::

(я надеюсь, что последний пример верен - или есть другое правило, если адрес оканчивается на 0?)

9 голосов
/ 27 января 2012

Недавно я столкнулся с той же проблемой и хотел бы (очень немного) улучшить ответ Тима.

Следующее регулярное выражение предлагает два преимущества:

((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)

Во-первых, оно включает в себя изменение для соответствия нескольким нулям.Во-вторых, он также правильно сопоставляет адреса, где самая длинная цепочка нулей находится в начале адреса (например, 0:0:0:0:0:0:0:1).

2 голосов
/ 26 марта 2013

java-ipv6 - это почти то, что вы хотите.Начиная с версии 0.10, он не проверяет, будет ли сокращен самый длинный цикл нулей с :: - например, 0: 0: 1 :: сокращен до :: 1: 0: 0: 0: 0: 0.Это очень неплохая библиотека для обработки адресов IPv6, и эта проблема должна быть исправлена ​​в версии 0.11 , так что библиотека соответствует RFC 5952 .

1 голос
/ 20 июня 2017

Класс Guava InetAddresses имеет toAddrString () , который форматирует в соответствии с RFC 5952.

0 голосов
/ 27 марта 2018

Библиотека Java с открытым исходным кодом IPAddress может делать, как описано, она предоставляет множество способов создания строк для IPv4 и / или IPv6, включая каноническую строку, которая для IPv6 соответствует rfc 5952. Отказ от ответственности: я руководитель проекта этой библиотеки.

Используя приведенные вами примеры, пример кода:

    IPAddress addr = new IPAddressString("2001:db8:0:0:0:0:2:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:db8::2:1
    addr = new IPAddressString("2001:db8:0:1:1:1:1:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:db8:0:1:1:1:1:1
    addr = new IPAddressString("2001:0:0:1:0:0:0:1").getAddress();
    System.out.println(addr.toCanonicalString());
    // 2001:0:0:1::1
    addr = new IPAddressString("2001:db8:0:0:1:0:0:1").getAddress();
    System.out.println(addr.toCanonicalString());
    //2001:db8::1:0:0:1
0 голосов
/ 01 июня 2014

После выполнения некоторых тестов, я думаю, что следующие снимки всех различных сценариев IPv6:

"((?:(?::0|0:0?)\\b){2,}):?(?!\\S*\\b\\1:0\\b)(\\S*)" -> "::$2"
...