必须先清理注释再提取title,因为preg_match无法区分注释与正文,直接匹配会误吞注释或包含注释内容;需用preg_replace清除html、php及shell注释,再用preg_match提取,但复杂场景推荐domdocument解析。

直接用 preg_match 提取 <title></title> 标签时,如果 HTML 里混着注释(比如 <!-- ... --> 或 <?php // ... ?>),正则会把注释当正文匹配进去,导致提取出错或截断。必须先清理注释,再提标题。
为什么不能边匹配边过滤注释
正则本身不区分“注释”和“标签内容”,/<title>(.*?)/si</title> 遇到 <!-- 注释 --><title>xxx</title> 会把注释当成前导空白吞掉;但如果注释在 title 标签内部(极少见但合法),比如 <title>abc<!-- def -->ghi</title>,默认正则会直接匹配整个内容,包含注释文本。
- HTML 注释
<!--.*?-->是独立语法单元,不在标签内容里,但会影响上下文位置 - PHP 注释(如
//、/* */)出现在内联 PHP 片段中时,可能干扰 DOM 结构解析 -
preg_match不做语法树解析,只按字符串模式走,没法“跳过注释区域”
先清理注释再提取 title 的可靠顺序
分两步:先用 preg_replace 去掉所有注释,再用 preg_match 提取 title。注意清理范围要覆盖 HTML 和内嵌 PHP 两种注释。
- HTML 注释:
preg_replace('/<!--[\s\S]*?-->/i', '', $html) - PHP 单行注释:
preg_replace('/\/\/.*?(?=\n|$)/', '', $html)(需加m修饰符才生效) - PHP 多行注释:
preg_replace('/\/\*.*?\*\//s', '', $html) - Shell 风格注释(#):
preg_replace('/#. *?(?=\n|$)/', '', $html)
建议合并成一条正则,避免多次遍历:
preg_replace('/(<!--[\s\S]*?-->)|(?:(?:\/\/|#).*?(?=\n|$))|(\/\*.*?\*\/)/s', '', $html)
提取 title 时仍需防注释残留的边界问题
即使清理过注释,某些边缘写法仍会让 preg_match 失效,比如:
- title 标签跨多行且中间有换行缩进:
<title>\n Hello\n</title>→ 要用s修饰符让.匹配换行 - title 内容含未转义的
或 <code>>(罕见但可能)→ 正则无法安全处理,应改用 DOM 解析 - 存在多个
<title></title>(如模板中动态拼接)→preg_match只返回第一个,preg_match_all才能全取
稳妥写法:
$clean_html = preg_replace('/(<!--[\s\S]*?-->)|(?:(?:\/\/|#).*?(?=\n|$))|(\/\*.*?\*\/)/s', '', $html);
preg_match('/<title>(.*?)/si', $clean_html, $matches);
$title = $matches[1] ?? '';</title>
真正麻烦的不是正则怎么写,而是你永远不知道输入 HTML 里藏着多少种注释嵌套、编码混淆或非标准写法。一旦遇到复杂页面,DOMDocument 加 getElementsByTagName('title') 比任何正则都靠谱。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











