Как я могу исправить это регулярное выражение? (результаты Nmap)

Я пытаюсь разобрать текст в 4 группы захвата, но я столкнулся с проблемой.

Мое регулярное выражение:

(\d{1,5})\/(tcp|udp)\s+open\s+(\S+)\s*(.*)?

Некоторые примеры ввода:

Nmap scan report for X
Host is up (0.097s latency).
Not shown: 192 closed ports
PORT     STATE         SERVICE       VERSION
135/udp  open          msrpc
137/udp  open          netbios-ns    Microsoft Windows XP netbios-ssn (workgroup: THINC)
135/tcp open  msrpc        Microsoft Windows RPC
139/tcp open  netbios-ssn  Microsoft Windows netbios-ssn
445/tcp open  microsoft-ds Windows XP microsoft-ds

Это работает почти идеально. Проблема в строке 135/udp, поле версии отсутствует, поэтому моя группа захвата 4 для этой строки оборачивается и захватывает всю следующую строку (начиная с 137/udp).

Я хотел бы, чтобы группа захвата 4 была пустой / нулевой для строки 135/udp (или в любом месте, где поле версии пустое).

Похоже мой последний .* не должен проходить через терминатор строки, но это так. Я также включил ? после моей последней группы захвата, чтобы попытаться сделать это необязательным, например, чтобы разрешить нулевое значение.

Кто-нибудь может указать, что я делаю не так? Было бы более полезно объяснить мою ошибку, чем просто предоставить мне рабочее выражение.

Визуальное представление

2 ответа

Решение

\s похоже, совпадают с новыми строками. Это неожиданно для меня - я бы ожидал \s соответствовать только пробелам.

Вместо этого попробуйте сопоставить только табуляцию и пробелы:[ \t] вместо \s,

и быть немного более требовательным, то есть устанавливать пробелы и непространства, которые ожидаются с +, не с *:

(\d{1,5})\/(tcp|udp)[ \t]+open[ \t]+(\S+)[ \t]+(.*)

(\S+) это одна запись ожидается после открытых и пробелов. Но так как нас интересуют только те строки, которые продолжаются после этого:[ \t]+ требует наличия пробела после этой записи (исключая строку, которая заканчивается там) - с (.*) захватывая все, что приходит после пробела.

Как указал bytepusher, у меня был символ \s, который соответствовал символам новой строки. Я заменил \s явным соответствием для пробелов или табуляций [ \t], как в:

(\d{1,5})\/(tcp|udp)\s+open\s+(\S+)[ \t]*(.*)?

Наиболее правильно, я заменил все экземпляры /s с явными совпадениями для ожидаемых пробелов:

(\d{1,5})\/(tcp|udp)[ \t]+open[ \t]+(\S+)[ \t]*(.*)?
Другие вопросы по тегам