| 76 | |
| 77 | @classmethod |
| 78 | def parse(cls, banner: str) -> Optional['Banner']: |
| 79 | valid_ascii = Utils.is_print_ascii(banner) |
| 80 | ascii_banner = Utils.to_print_ascii(banner) |
| 81 | mx = cls.RX_BANNER.match(ascii_banner) |
| 82 | if mx is None: |
| 83 | return None |
| 84 | protocol = min(re.findall(cls.RX_PROTOCOL, mx.group(1))) |
| 85 | protocol = (int(protocol[0]), int(protocol[1])) |
| 86 | software = (mx.group(3) or '').strip() or None |
| 87 | if software is None and (mx.group(2) or '').startswith('-'): |
| 88 | software = '' |
| 89 | comments = (mx.group(4) or '').strip() or None |
| 90 | if comments is not None: |
| 91 | comments = re.sub(r'\s+', ' ', comments) |
| 92 | return cls(protocol, software, comments, valid_ascii) |