我正在尝试使用正则表达式验证 Youtube URL:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+~', $videoLink)
它确实有效,但它可以匹配格式错误的 URL。例如,这样就可以匹配:
http://www.youtube.com/watch?v=Zu4WXiPRek
但是这也会:
http://www.youtube.com/watch?v=Zu4WX£&P!ek
这不会:
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
我认为这是因为
+
运算符。当它需要尝试将 v=
后面的所有内容与 v=
匹配时,它会匹配 [a-zA-Z0-9-]
之后的第一个字符。感谢任何帮助,谢谢。
提供一个比正则表达式更大、更不优雅的替代方案,但可以与 PHP 的本机 URL 解析函数配合使用,因此从长远来看它可能更可靠:
$url = "http://www.youtube.com/watch?v=Zu4WXiPRek";
$query_string = parse_url($url, PHP_URL_QUERY); // v=Zu4WXiPRek
$query_string_parsed = array();
parse_str($query_string, $query_string_parsed); // an array with all GET params
echo($query_string_parsed["v"]); // Will output Zu4WXiPRek that you can then
// validate for [a-zA-Z0-9] using a regex
问题是您不需要 URL 的 v= 部分包含任何特定数量的字符。例如,检查
http://www.youtube.com/watch?v=Zu4WX£&P!ek
将匹配
http://www.youtube.com/watch?v=Zu4WX
因此返回 true。您需要在 v= 部分指定所需的字符数:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]{10}~', $videoLink)
或指定组 [a-zA-Z0-9-] 必须是字符串的最后部分:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+$~', $videoLink)
你的另一个例子
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
不匹配,因为+号要求至少有一个字符必须匹配[a-zA-Z0-9-]。
简短回答:
preg_match('%(http://www.youtube.com/watch\?v=(?:[a-zA-Z0-9-])+)(?:[&"\'\s])%', $videoLink)
这里做了一些假设,所以让我解释一下:
( ... )
部分添加了一个捕获组 http://www.youtube.com/watch?v=blah
,这样我们就可以说“我想要获取整个经过验证的链接,包括 ?v=movieHash”(?: ... )
周围添加了非捕获组[a-zA-Z0-9-]
,并将+号留在了外面。这将使我们能够在一定程度上匹配所有允许的字符。最重要的是,您需要告诉它您期望您的链接如何终止。我来帮你猜猜
(?:[&"\'\s])
?)它会是 html 格式(例如锚标记)吗?如果是这样,href中的链接显然将以“或'结束。
?)或者查询字符串可能还有更多内容,因此在 v 的值后面会有一个 &。
?)链接末尾后可能有空格或换行符\s。
重要的是,如果您知道要搜索的内容周围有什么,则可以获得更准确的结果,就像许多正则表达式的情况一样。
这个非捕获组(我在其中为你做出假设)将尝试找到并忽略在你关心的内容之后的所有额外垃圾(?v=awesomeMovieHash)。
结果:
http://www.youtube.com/watch?v=Zu4WXiPRek
- Group 1 contains the http://www.youtube.com/watch?v=Zu4WXiPRek
http://www.youtube.com/watch?v=Zu4WX&a=b
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
- No match
a href="http://www.youtube.com/watch?v=Zu4WX&size=large"
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=Zu4WX£&P!ek
- No match
“v=...” blob 不保证是 URL 查询部分中的第一个参数。我建议使用 PHP 的 parse_url() 函数将 URL 分解为其组成部分。如果有人以“https://”开头字符串或简单地使用“youtube.com”而不是“www.youtube.com”等,您还可以重新组装原始 URL。
function get_youtube_vidid ($url) {
$vidid = false;
$valid_schemes = array ('http', 'https');
$valid_hosts = array ('www.youtube.com', 'youtube.com');
$valid_paths = array ('/watch');
$bits = parse_url ($url);
if (! is_array ($bits)) {
return false;
}
if (! (array_key_exists ('scheme', $bits)
and array_key_exists ('host', $bits)
and array_key_exists ('path', $bits)
and array_key_exists ('query', $bits))) {
return false;
}
if (! in_array ($bits['scheme'], $valid_schemes)) {
return false;
}
if (! in_array ($bits['host'], $valid_hosts)) {
return false;
}
if (! in_array ($bits['path'], $valid_paths)) {
return false;
}
$querypairs = explode ('&', $bits['query']);
if (count ($querypairs) < 1) {
return false;
}
foreach ($querypairs as $querypair) {
list ($key, $value) = explode ('=', $querypair);
if ($key == 'v') {
if (preg_match ('/^[a-zA-Z0-9\-_]+$/', $value)) {
# Set the return value
$vidid = $value;
}
}
}
return $vidid;
}
以下正则表达式将匹配任何 YouTube 链接:
$pattern='@(((http(s)?://(www\.)?)|(www\.)|\s)(youtu\.be|youtube\.com)/(embed/|v/|watch(\?v=|\?.+&v=|/))?([a-zA-Z0-9._\/~#&=;%+?-\!]+))@si';
^(?:(?:https?:)?\/\/)?(?:(?:(?:www|m(?:usic)?)\.)?youtu(?:\.be|be(?:-nocookie)?\.com))\/(?:shorts\/|live\/|v\/|embed\/|watch(?:\/|\?(?:\S+=\S+&)*v=)|oembed\?url=https?%3A\/\/(?:www|m(?:usic)?)\.youtube(?:-nocookie)?\.com\/watch\?(?:\S+=\S+&)*v%3D|attribution_link\?(?:\S+=\S+&)*u=(?:\/|%2F)watch(?:\?|%3F)v(?:=|%3D)|playlist\?(?:\S+=\S+&)*list=)?([\w-]+)[\?&#]?\S*$
从任何已知的 YouTube URL(还有音乐、短片、现场、嵌入、nocookie 等)中提取视频 ID。这是相关问题下的答案https://stackoverflow.com/a/78172756/11194000
如果您愿意,可以在正则表达式中使用
{11}
而不是 +
将视频 ID 限制为 11 个字符。