Извлечь комбо хоста/порта с .net regex - часть порта необязательна
Скажем, я хочу извлечь имя хоста и номер порта из строки следующим образом:
stackoverflow.com:443
Это довольно легко. Я мог бы сделать что-то вроде этого:
(?<host>.*):(?<port>\d*)
Я не беспокоюсь о схемах протоколов или действительных именах хостов/IP-адресах или портах tcp/udp, это не важно для моего запроса.
Тем не менее, мне также нужно поддерживать один твист, который делает это выше моих знаний о регулярных выражениях - имя хоста без порта:
stackoverflow.com
Я хочу использовать одно регулярное выражение для этого, и я хочу использовать именованные группы захвата, чтобы группа хостов всегда существовала в положительном совпадении, тогда как группа портов существует тогда и только тогда, когда у нас есть двоеточие, за которым следуют несколько цифр.
Я попытался сделать положительный взгляд из моего слабого понимания этого:
(?<host>.*)(?<=:)(?<port>\d*)
Это близко, но двоеточие (:) включено в конце захвата хоста. Поэтому я попытался изменить хост, чтобы включить что-либо, кроме двоеточия, как это:
(?<host>[^:]*)(?<=:)(?<port>\d*)
Это дает мне пустой захват хоста.
Любые предложения о том, как это сделать, т.е. сделать двоеточие и номер порта необязательными, но если они есть, включите захват номера порта и сделайте двоеточие "исчезающим"?
Изменить: Все четыре ответа, которые я получил, хорошо работают для меня, но обратите внимание на комментарии в некоторых из них. Я принял sln-ответ из-за хорошей компоновки и объяснения структуры regexp. Спасибо всем, кто ответил!
Ответы
Ответ 1
Это может быть (?<host>[^:]+)(?::(?<port>\d+))?
(?<host> [^:]+ ) # (1), Host, required
(?: # Cluster group start, optional
: # Colon ':'
(?<port> \d+ ) # (2), Port number
)? # Cluster group end
edit - Если вы не должны использовать кластерную группу и вместо этого использовать группу захвата в качестве этой группы кластеров, так Dot-Net "подсчитывает" группы в состоянии конфигурации по умолчанию -
(?<host> [^:]+ ) #_(2), Host, required
( # (1 start), Unnamed capture group, optional
: # Colon ':'
(?<port> \d+ ) #_(3), Port number
)? # (1 end)
Ответ 2
Я предлагаю использовать класс 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
Ответ 3
Если ваше имя хоста не содержит :
, например, ipv64, попробуйте следующее:
(?<host>[^:]*):?(?<port>\d*)
Ответ 4
Попробуйте следующее:
(?<host>[^:]+)(:(?<port>\d+))?
Это делает всю часть номера двоеточия и номера порта необязательной группой и ловит в ней номер порта. Кроме того, я использовал знак плюса, чтобы гарантировать, что имя хоста и номер порта содержат хотя бы один символ.
Ответ 5
Вы можете использовать это:
(?<host>[^:]+)(:(?<port>\\d+))?