Извлеките комбо хост / порт с помощью.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
Если ваше имя хоста не содержит :
как ipv64, попробуйте это:
(?<host>[^:]*):?(?<port>\d*)
Попробуй это:
(?<host>[^:]+)(:(?<port>\d+))?
Это делает целую часть двоеточия и номера порта необязательной группой и перехватывает номер порта внутри нее. Кроме того, я использовал знак плюс, чтобы имя хоста и номер порта содержали хотя бы один символ.