如何使用正则表达式在字符串中查找所有YouTube视频的ID?

95

我有一个文本框,用户可以在里面写任何东西。

例如:

Lorem Ipsum是虚拟的印刷样例文字。 http://www.youtube.com/watch?v=DUQi_R4SgWo 自15世纪以来一直是印刷和排版行业的标准虚拟文字,当时一位未知的印刷工人使用活字印刷技术制作了一本样本书。它不仅经历了五个世纪,同时也迎来了电子排版的飞跃,并保持着基本不变的状态。 http://www.youtube.com/watch?v=A_6gNZCkajU&feature=relmfu 它是在20世纪60年代随着Letraset传单的发布而流行的,其中包含了Lorem Ipsum的段落,并且还有桌面出版软件Aldus PageMaker,包括版本的Lorem Ipsum.

现在我想解析它并找到所有YouTube视频的URL和它们的ID。

你有什么想法吗?


1
可能是重复的问题:[Javascript REGEX:如何从URL获取YouTube视频ID?](https://dev59.com/W3A75IYBdhLWcg3wJFcL) - T.Todua
10个回答

297

YouTube视频的URL可能以多种格式出现:

  • 最新的短格式:http://youtu.be/NLqAF9hrVbY
  • iframe:http://www.youtube.com/embed/NLqAF9hrVbY
  • iframe(安全版):https://www.youtube.com/embed/NLqAF9hrVbY
  • 对象参数:http://www.youtube.com/v/NLqAF9hrVbY?fs=1&hl=en_US
  • 对象嵌入:http://www.youtube.com/v/NLqAF9hrVbY?fs=1&hl=en_US
  • 观看:http://www.youtube.com/watch?v=NLqAF9hrVbY
  • 用户:http://www.youtube.com/user/Scobleizer#p/u/1/1p3vcRhsYGo
  • ytscreeningroom:http://www.youtube.com/ytscreeningroom?v=NRHVzbJVx8I
  • 任意/thing/goes!:http://www.youtube.com/sandalsResorts#p/c/54B8C800269D7C1B/2/PPS-8DMrAn4
  • 任意子域名/too:http://gdata.youtube.com/feeds/api/videos/NLqAF9hrVbY
  • 更多参数:http://www.youtube.com/watch?v=spDj54kf-vY&feature=g-vrec
  • 查询可能带有点:http://www.youtube.com/watch?v=spDj54kf-vY&feature=youtu.be
  • nocookie域名:http://www.youtube-nocookie.com

这里有一个PHP函数,其中包含有注释的正则表达式,可以匹配这些URL格式并将它们转换为链接(如果它们还不是链接):

// Linkify youtube URLs which are not already links.
function linkifyYouTubeURLs($text) {
    $text = preg_replace('~(?#!js YouTubeId Rev:20160125_1800)
        # Match non-linked youtube URL in the wild. (Rev:20130823)
        https?://          # Required scheme. Either http or https.
        (?:[0-9A-Z-]+\.)?  # Optional subdomain.
        (?:                # Group host alternatives.
          youtu\.be/       # Either youtu.be,
        | youtube          # or youtube.com or
          (?:-nocookie)?   # youtube-nocookie.com
          \.com            # followed by
          \S*?             # Allow anything up to VIDEO_ID,
          [^\w\s-]         # but char before ID is non-ID char.
        )                  # End host alternatives.
        ([\w-]{11})        # $1: VIDEO_ID is exactly 11 chars.
        (?=[^\w-]|$)       # Assert next char is non-ID or EOS.
        (?!                # Assert URL is not pre-linked.
          [?=&+%\w.-]*     # Allow URL (query) remainder.
          (?:              # Group pre-linked alternatives.
            [\'"][^<>]*>   # Either inside a start tag,
          | </a>           # or inside <a> element text contents.
          )                # End recognized pre-linked alts.
        )                  # End negative lookahead assertion.
        [?=&+%\w.-]*       # Consume any URL (query) remainder.
        ~ix', '<a href="http://www.youtube.com/watch?v=$1">YouTube link: $1</a>',
        $text);
    return $text;
}

; // 结束$YouTubeId。

这里是一个使用相同正则表达式的JavaScript版本(已删除注释):

// Linkify youtube URLs which are not already links.
function linkifyYouTubeURLs(text) {
    var re = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\S*?[^\w\s-])([\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig;
    return text.replace(re,
        '<a href="http://www.youtube.com/watch?v=$1">YouTube link: $1</a>');
}

注意:

  • URL的VIDEO_ID部分被捕获在唯一的捕获组中:$1
  • 如果您知道您的文本不包含任何预链接的URL,可以安全地删除否定前瞻断言,该断言测试此条件(以注释开头:“断言URL未预链接”)。这将加快正则表达式的速度。
  • 替换字符串可以修改以适应。上面提供的只是创建链接到通用"http://www.youtube.com/watch?v=VIDEO_ID"风格URL并将链接文本设置为:"YouTube link: VIDEO_ID"

编辑2011-07-05:在ID字符类中添加了-连字符

编辑2011-07-17:修复了正则表达式以消耗遵循YouTube ID的URL的任何剩余部分(例如查询)。添加了'i' 忽略大小写修饰符。将函数重命名为camelCase。改进了预链接的前瞻测试。

编辑2011-07-27:添加了新的“用户”和“ytscreeningroom”格式的YouTube URL。

编辑2011-08-02:简化/概括以处理新的“任何/事情/走”YouTube URL。

编辑2011-08-25:进行了几个修改:

  • 添加了linkifyYouTubeURLs()函数的JavaScript版本。
  • 先前的版本使方案(HTTP协议)部分可选,因此会匹配无效的URL。将方案部分设为必需。
  • 以前的版本在VIDEO_ID周围使用了\b单词边界锚定符号。但是,如果VIDEO_ID以-破折号开头或结尾,则无法使用该符号。修复以处理此条件。
  • 更改VIDEO_ID表达式,使其必须正好为11个字符长。
  • 以前的版本未排除具有VIDEO_ID后跟查询字符串的预链接URL。改进了否定前瞻断言以解决此问题。
  • 将“+”和“%”添加到与查询字符串匹配的字符类。
  • 将PHP版本的正则表达式分隔符从%更改为~
  • 添加了一个“注意事项”部分,其中包含一些方便的说明。

编辑2011-10-12: YouTube URL主机部分现在可以有任何子域(不仅仅是www.)。

编辑2012-05-01: 消耗URL部分现在可能允许“-”。

编辑2013-08-23: 添加了由@Mei提供的其他格式。(查询部分可能具有一个.点)。

编辑2013-11-30: 添加了由@CRONUS提供的其他格式:youtube-nocookie.com

编辑2016-01-25: 修正了由CRONUS提供的错误情况所示的正则表达式。


2
我没有看到规格说明,但我确实找到了一个。我只是注意到互联网上一些链接中有破折号。例如:http://www.youtube.com/watch?v=CLPk-6_xgiY - cottonBallPaws
1
@littleFluffyKitty:谢谢你提醒。已经更新答案,将连字符作为有效的ID字符包含在内。 - ridgerunner
1
@ridgerunner:如果您对编辑不太自信,可以回滚。此外,就像维基百科一样,整个历史记录都会保留您的贡献。我看到您随着时间的推移真正精心地维护了答案,所以失去您将是一件遗憾的事情。 - hakre
1
这个很好用,但是在这个(新的?)查询字符串参数feature=youtu.be下失败了。将[?=&+%\w-]*更改为[?=&+%\w-.]*在您的“消耗剩余URL”行上就可以解决问题了。谢谢! - Mei Gwilym
1
当t是第一个参数时,此链接不起作用:https://www.youtube.com/watch?t=48&v=Opcu8ZJYE6 - Lane
显示剩余44条评论

10

这是我曾经为一个项目编写的一种方法,可以提取YouTube和Vimeo视频的key:

/**
 *  strip important information out of any video link
 *
 *  @param  string  link to a video on the hosters page
 *  @return mixed  FALSE on failure, array on success
 */
function getHostInfo ($vid_link)
{
  // YouTube get video id
  if (strpos($vid_link, 'youtu'))
  {
    // Regular links
    if (preg_match('/(?<=v\=)([\w\d-_]+)/', $vid_link, $matches))
      return array('host_name' => 'youtube', 'original_key' => $matches[0]); 
    // Ajax hash tag links
    else if (preg_match('§([\d\w-_]+)$§i', $vid_link, $matches))
      return array('host_name' => 'youtube', 'original_key' => $matches[0]);
    else
      return FALSE;
  }
  // Vimeo get video id
  elseif (strpos($vid_link, 'vimeo'))
  {
    if (preg_match('§(?<=/)([\d]+)§', $vid_link, $matches))
      return array('host_name' => 'vimeo', 'original_key' => $matches[0]); 
    else
      return FALSE;
  }
  else
    return FALSE;
}
  1. 找到一个正则表达式,可以从文本中提取所有链接。谷歌会帮助你。
  2. 循环所有链接,并为每个链接调用getHostInfo()函数。

1
非常感谢!稍作修改 if(strpos($vid_link, 'youtu')) 将捕获短网址 youtu.be 以及常见的网址。 - Chamilyan
不客气。谢谢你的更新,我已经修改了更改。另外,Ridgerunner的正则表达式似乎非常有效,我建议使用它而不是我的简单工具。祝福! - Christof
正是我所寻找的。太准确了,伙计!+1 - Malitta N

7
虽然ridgerunner的答案是我回答的基础,但他的方法并不能解决所有URL,我认为由于YouTube URL中VIDEO_ID可能有多个匹配项,他的方法无法胜任。我的正则表达式包含了他的积极方法作为最后一招,但首先尝试所有常见的匹配,大大降低了URL后面出现错误匹配的可能性。

这个正则表达式:

/https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\/ytscreeningroom\?v=|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))([\w\-]{11})[?=&+%\w-]*/ig;

处理所有在ridgerunners示例中提到的情况,以及任何可能在URL后面有11个字符序列的URL。例如:

http://www.youtube.com/watch?v=GUEZCxBcM78&feature=pyv&feature=pyv&ad=10059374899&kw=%2Bwingsuit

这里有一个有效的示例,测试所有样本YouTube网址:

http://jsfiddle.net/DJSwc/5/


2

原帖提问:“我想解析它并找到所有YouTube视频的URL和ID。” 我将上面最受欢迎的答案改为preg_match,并返回了视频ID和URL。

从帖子中获取YouTube URL和ID:

$match[0] = Full URL
$match[1] = video ID

function get_youtube_id($input) {
    $input = preg_match('~https?://(?:[0-9A-Z-]+\.)?(?:youtu\.be/|youtube(?:-nocookie)?\.com\S*[^\w\s-])([\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:[\'"][^<>]*>|</a>))[?=&+%\w.-]*~ix',
                        $input, $match);
    return $match;
}

2

使用:

<?php

    // The YouTube URL string

    $youtube_url='http://www.youtube.com/watch?v=8VtUYvwktFQ';

    // Use regex to get the video ID

    $regex='#(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=[0-9]/)[^&\n]+|(?<=v=)[^&\n]+#';

    preg_match($regex, $youtube_url, $id);

    // Plug that into our HTML
?>

2

好的,我写了一个自己的函数。但我认为它效率不高。 欢迎提出改进意见:

function get_youtube_videos($string) {

    $ids = array();

    // Find all URLs
    preg_match_all('/(http|https)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/', $string, $links);

    foreach ($links[0] as $link) {
        if (preg_match('~youtube\.com~', $link)) {
            if (preg_match('/[^=]+=([^?]+)/', $link, $id)) {
                $ids[] = $id[1];
            }
        }
    }
    return $ids;
}

如果你只想要来自youtube.com的链接,为什么要首先建立一个包含所有链接的列表呢?而且我认为使用3个不同的正则表达式是不必要的。 - stema

2

尝试

[^\s]*youtube\.com[^\s]*?v=([-\w]+)[^\s]*

你会在第一个捕获组中找到视频ID。我不知道什么样的视频ID是有效的?目前,我检查 v= 并捕获所有 -A-Za-z0-9_
我在rubular上使用你提供的字符串进行了在线验证。

1
我尝试了一个简单的表达式来仅获取视频ID:
[?&]v=([^&#]*)

请在phpliveregex上在线检查其是否正常工作。


0
String urlid="" ;
String  url="http://www.youtube.com/watch?v=0zM4nApSvMg#t=0m10s";
Pattern pattern =Pattern.compile("(?:http|https|)(?::\\/\\/|)(?:www.|)(?:youtu\\.be\\/|youtube\\.com(?:\\/embed\\/|\\/v\\/|\\/watch\\?v=|\\/ytscreeningroom\\?v=|\\/feeds\\/api\\/videos\\/|\\/user\\\\S*[^\\w\\-\\s]|\\S*[^\\w\\-\\s]))([\\w\\-\\_]{11})[a-z0-9;:@#?&%=+\\/\\$_.-]*");
Matcher result = pattern.matcher(url);
    if (result.find())
    {
         urlid=result.group(1);

    }

目前,这段Java代码对于所有YouTube链接都可以完美运行。


0

从字符串中轻松找到YouTube链接:

function my_url_search($se_action_data)
{
    $regex = '/https?\:\/\/[^\" ]+/i';
    preg_match_all($regex, $se_action_data, $matches);
    $get_url=array_reverse($matches[0]);
    return array_unique($get_url);
}
echo my_url_search($se_action_data)

这不仅适用于YouTube,它还可以匹配其他内容的URL。 - Rahil Wazir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接