PHP技术问询:如何从字符串中提取有效域名与IPv4地址?
解决方案
1. 核心思路
原来的正则会误抓相对路径,主要是没区分「域名/IP」和「本地路径」,也没适配新顶级域名(比如.app、.dev),更没加IPv4匹配规则。这次的正则会:
- 只抓取合法的绝对域名(带/不带http/https前缀都支持),自动排除本地相对路径
- 精准匹配合法IPv4地址
- 自动截断域名/IP后面的路径、查询参数(比如
https://example.com/path?a=1只会抓取https://example.com)
2. 可用代码
// 匹配域名(带/不带http前缀)和IPv4,自动截断后续路径/参数 $pattern = '# (?:https?://)? # 可选的http/https前缀,不单独捕获 (?: # 匹配合法域名:二级域+顶级域,符合ICANN规范 (?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,} | # 匹配合法IPv4:每个段0-255,格式严谨 (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) ) (?:/|\?|$) # 匹配域名/IP后的分隔符,用来截断后续内容 #ix'; preg_match_all($pattern, $response->body(), $matches); // 去重+清理末尾可能残留的/或? $cleanResults = array_unique(array_map(function($item) { return rtrim($item, '/?'); }, $matches[0])); print_r($cleanResults);
3. 规则拆解
(?:https?://)?:允许域名带或不带http/https前缀,?:是为了不让这个前缀单独成为匹配结果,只作为域名的一部分。- 域名规则:每个域名段(比如
example、com)最长63字符,只能是字母、数字和连字符,且不能以连字符开头/结尾,顶级域至少2位(适配所有新顶级域)。 - IPv4规则:严格校验每个IP段在0-255之间,避免匹配像
999.999.999.999这种无效IP。 (?:/|\?|$):当匹配到域名/IP后,遇到/(路径开头)、?(查询参数开头)或者字符串结束就停止,自动截断后面的冗余内容。- 修饰符
i:不区分大小写(比如Example.COM也能匹配);x:忽略正则里的空格,方便查看规则结构。
4. 解决原问题的关键
- 排除相对路径:本地相对路径(比如
/html/style/global.css.php)不符合域名结构(没有合法的顶级域前的域名段),所以不会被匹配到。 - 一次搞定两种匹配:把域名和IPv4的规则放在同一个分支里,一次
preg_match_all就能拿到所有目标结果。 - 自动去冗余:通过正则末尾的分隔符匹配,直接去掉后面的路径和参数,不用额外处理。
内容的提问来源于stack exchange,提问作者kamilon123s
相关产品推荐
相关产品推荐

