Извлеките комбо хост / порт с помощью.net regex - необязательная часть порта

Скажем, я хочу извлечь имя хоста и номер порта из такой строки:

stackru.com:443

Это довольно легко. Я мог бы сделать что-то вроде этого:

(?<host>.*):(?<port>\d*)

Я не беспокоюсь о схемах протоколов или действительных именах хостов / IP-адресах или портах tcp / udp, это не важно для моего запроса.

Однако мне также нужно поддерживать один поворот, который выходит за рамки моих знаний о регулярных выражениях - имя хоста без порта:

stackru.com

Я хочу использовать для этого одно регулярное выражение, и я хочу использовать именованные группы перехвата, чтобы группа хостов всегда существовала в положительном соответствии, тогда как группа портов существует тогда и только тогда, когда у нас есть двоеточие, за которым следует число цифры.

Я попытался сделать положительный взгляд из-за моего слабого понимания этого:

(?<host>.*)(?<=:)(?<port>\d*)

Это близко, но двоеточие (:) включается в конце захвата хоста. Поэтому я попытался изменить хост так, чтобы он включал что-либо, кроме двоеточия, например так:

(?<host>[^:]*)(?<=:)(?<port>\d*)

Это дает мне пустой захват хоста.

Любые предложения о том, как сделать это, например, сделать двоеточие и номер порта необязательными, но если они есть, включить захват номера порта и заставить двоеточие "исчезнуть"?

Изменить: Все четыре ответа, которые я получил, хорошо работают для меня, но обратите внимание на комментарии в некоторых из них. Я принял ответ sln из-за хорошего расположения и объяснения структуры регулярных выражений. Спасибо всем, что ответили!

5 ответов

Решение

Это может быть (?<host>[^:]+)(?::(?<port>\d+))?

 (?<host> [^:]+ )               # (1), Host, required
 (?:                            # Cluster group start, optional
      :                              # Colon ':'
      (?<port> \d+ )                 # (2), Port number
 )?                             # Cluster group end

редактировать - если вы не хотите использовать группу кластеров, а вместо этого использовать группу захвата в качестве этой группы кластеров, именно так Dot-Net "считает" группы в своем состоянии конфигурации по умолчанию -

 (?<host> [^:]+ )         #_(2), Host, required                           
 (                        # (1 start), Unnamed capture group, optional
      :                        # Colon ':'
      (?<port> \d+ )           #_(3), Port number                           
 )?                       # (1 end)

Я предлагаю использовать класс Uri вместо регулярных выражений.

// Use URI class for parsing only
var uri = new Uri("http://" + fullAddress);
// get host
host = uri.DnsSafeHost;
// get port
portNum = (ushort)uri.Port;

Преимущества

  • Поддерживает:
    • IPv4 и IPv6
    • Интернационализированное доменное имя ( IDN)
  • Может быть расширен для учета схемы в будущем
  • Короткий и стандартизированный код, поэтому ошибок меньше

Смотрите пример использования на .NET Fiddle

Вы можете использовать это:

(?<host>[^:]+)(:(?<port>\\d+))?

Если ваше имя хоста не содержит : как ipv64, попробуйте это:

(?<host>[^:]*):?(?<port>\d*)

Попробуй это:

(?<host>[^:]+)(:(?<port>\d+))?

Это делает целую часть двоеточия и номера порта необязательной группой и перехватывает номер порта внутри нее. Кроме того, я использовал знак плюс, чтобы имя хоста и номер порта содержали хотя бы один символ.

Другие вопросы по тегам