如何修复正则以从各类YouTube URL提取Video Id与start time并兼容播放列表?
YouTube URL提取Video ID与起始时间的完整解决方案
一、多格式兼容的preg_match正则实现
以下正则可适配绝大多数YouTube URL,精准提取11位Video ID和start参数对应的起始时间(单位秒),解决了URL尾部解析不当的问题:
$pattern = '/^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/|playlist\?list=.*?&v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\?.*?start=(\d+))?(?:&.*|$)/i'; // 测试示例 $testUrls = [ 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', 'https://youtu.be/dQw4w9WgXcQ?start=30', 'https://www.youtube.com/embed/dQw4w9WgXcQ?start=15&autoplay=1', 'https://www.youtube.com/v/dQw4w9WgXcQ', 'https://www.youtube.com/shorts/dQw4w9WgXcQ?start=5', 'https://www.youtube.com/playlist?list=PLxyz&v=dQw4w9WgXcQ&start=10' ]; foreach ($testUrls as $url) { if (preg_match($pattern, $url, $matches)) { $videoId = $matches[1]; $startTime = isset($matches[2]) ? (int)$matches[2] : 0; echo "视频ID: {$videoId}, 起始时间: {$startTime} 秒\n"; } }
正则各部分解析
^(?:https?:\/\/)?(?:www\.)?:匹配可选的HTTP/HTTPS协议和www前缀,兼容无协议或无www的URL(?:youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/|playlist\?list=.*?&v=)|youtu\.be\/):覆盖YouTube核心路径,包括普通观看页、嵌入页、旧版路径、短视频页、播放列表内嵌视频链接([a-zA-Z0-9_-]{11}):强制捕获11位的Video ID(YouTube视频ID长度固定为11位,确保匹配精准)(?:\?.*?start=(\d+))?:非贪婪匹配并捕获start参数的数值,避免被后续URL参数干扰(?:&.*|$):匹配剩余URL参数或结尾,解决尾部解析混乱问题i修饰符:忽略大小写,兼容大小写混合的URL
二、已覆盖的URL格式
上述正则支持所有主流YouTube URL格式:
- 标准观看页:
https://www.youtube.com/watch?v=XXX - 短域名跳转链接:
https://youtu.be/XXX - 嵌入页链接:
https://www.youtube.com/embed/XXX - 旧版视频路径:
https://www.youtube.com/v/XXX - Shorts短视频链接:
https://www.youtube.com/shorts/XXX - 播放列表内嵌视频链接:
https://www.youtube.com/playlist?list=PLxxx&v=XXX - 带任意额外参数的上述格式(如
autoplay、loop等)
可扩展的边缘格式
若需覆盖更小众的场景,可对正则进行扩展:
- 锚点时间戳:如
https://www.youtube.com/watch?v=XXX#t=1m30s,可在正则末尾添加(?:#t=(\d+m?\d+s?))?,再将时分秒格式转换为总秒数 - 无Cookie域名:
https://www.youtube-nocookie.com/embed/XXX,可在域名匹配段加入|youtube-nocookie\.com - 自定义协议:如
youtube://watch?v=XXX,可在开头添加(?:youtube:\/\/)?
三、播放列表场景处理
若需同时提取播放列表ID和当前视频信息,可使用以下扩展正则:
$playlistPattern = '/^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?v=([a-zA-Z0-9_-]{11})&list=([a-zA-Z0-9_-]+)|playlist\?list=([a-zA-Z0-9_-]+)(?:&v=([a-zA-Z0-9_-]{11}))?)|youtu\.be\/([a-zA-Z0-9_-]{11}))(?:\?.*?start=(\d+))?(?:&.*|$)/i';
该正则可适配两种播放列表链接格式:
- 观看页带播放列表参数:
https://www.youtube.com/watch?v=XXX&list=PLxxx - 播放列表页指定视频:
https://www.youtube.com/playlist?list=PLxxx&v=XXX
四、兼容PHPStan的代码实现
为通过PHPStan静态分析,需明确变量类型、处理可选捕获组,示例代码如下:
/** * 从YouTube URL提取视频ID和起始时间 * @param string $url * @return array{videoId: string|null, startTime: int} */ function extractYoutubeVideoInfo(string $url): array { $pattern = '/^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?v=|embed\/|v\/|shorts\/|playlist\?list=.*?&v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\?.*?start=(\d+))?(?:&.*|$)/i'; if (preg_match($pattern, $url, $matches)) { $videoId = $matches[1]; $startTime = isset($matches[2]) ? (int)$matches[2] : 0; return ['videoId' => $videoId, 'startTime' => $startTime]; } return ['videoId' => null, 'startTime' => 0]; }
内容的提问来源于stack exchange,提问作者Zoltán Süle
相关产品推荐
相关产品推荐

