@@ -560,6 +560,8 @@ def __reduce__(self):
560560 return self .__class__ , (str (self ),)
561561
562562
563+ _address_fmt_re = None
564+
563565@functools .total_ordering
564566class _BaseAddress (_IPAddressBase ):
565567
@@ -623,72 +625,49 @@ def __format__(self, fmt):
623625
624626 Supported presentation types are:
625627 's': returns the IP address as a string (default)
626- 'b' or 'n' : converts to binary and returns a zero-padded string
628+ 'b': converts to binary and returns a zero-padded string
627629 'X' or 'x': converts to upper- or lower-case hex and returns a zero-padded string
630+ 'n': the same as 'b' for IPv4 and 'x' for IPv6
628631
629632 For binary and hex presentation types, the alternate form specifier
630633 '#' and the grouping option '_' are supported.
631634 """
632635
633-
634636 # Support string formatting
635637 if not fmt or fmt [- 1 ] == 's' :
636- # let format() handle it
637638 return format (str (self ), fmt )
638639
639640 # From here on down, support for 'bnXx'
641+ global _address_fmt_re
642+ if _address_fmt_re is None :
643+ import re
644+ _address_fmt_re = re .compile ('(#?)(_?)([xbnX])' )
640645
641- import re
642- fmt_re = '^(?P<alternate>#?)(?P<grouping>_?)(?P<fmt_base>[xbnX]){1}$'
643- m = re .match (fmt_re , fmt )
646+ m = _address_fmt_re .fullmatch (fmt )
644647 if not m :
645648 return super ().__format__ (fmt )
646649
647- groupdict = m .groupdict ()
648- alternate = groupdict ['alternate' ]
649- grouping = groupdict ['grouping' ]
650- fmt_base = groupdict ['fmt_base' ]
650+ alternate , grouping , fmt_base = m .groups ()
651651
652652 # Set some defaults
653653 if fmt_base == 'n' :
654654 if self ._version == 4 :
655655 fmt_base = 'b' # Binary is default for ipv4
656- if self . _version == 6 :
656+ else :
657657 fmt_base = 'x' # Hex is default for ipv6
658658
659- # Handle binary formatting
660659 if fmt_base == 'b' :
661- if self ._version == 4 :
662- # resulting string is '0b' + 32 bits
663- # plus 7 _ if needed
664- padlen = IPV4LENGTH + 2 + (7 * len (grouping ))
665- elif self ._version == 6 :
666- # resulting string is '0b' + 128 bits
667- # plus 31 _ if needed
668- padlen = IPV6LENGTH + 2 + (31 * len (grouping ))
669-
670- # Handle hex formatting
671- elif fmt_base in 'Xx' :
672- if self ._version == 4 :
673- # resulting string is '0x' + 8 hex digits
674- # plus a single _ if needed
675- padlen = int (IPV4LENGTH / 4 )+ 2 + len (grouping )
676- elif self ._version == 6 :
677- # resulting string is '0x' + 32 hex digits
678- # plus 7 _ if needed
679- padlen = int (IPV6LENGTH / 4 )+ 2 + (7 * len (grouping ))
680-
681- retstr = f'{ int (self ):#0{padlen }{grouping }{fmt_base }} '
660+ padlen = self ._max_prefixlen
661+ else :
662+ padlen = self ._max_prefixlen // 4
682663
683- if fmt_base == 'X' :
684- retstr = retstr . upper ()
664+ if grouping :
665+ padlen += padlen // 4 - 1
685666
686- # If alternate is not set, strip the two leftmost
687- # characters ('0b')
688- if not alternate :
689- retstr = retstr [2 :]
667+ if alternate :
668+ padlen += 2 # 0b or 0x
690669
691- return retstr
670+ return format ( int ( self ), f' { alternate } 0 { padlen } { grouping } { fmt_base } ' )
692671
693672
694673@functools .total_ordering
0 commit comments