【问题标题】:Improving regex for parsing YouTube / Vimeo URLs改进用于解析 YouTube / Vimeo URL 的正则表达式
【发布时间】:2011-08-02 12:37:58
【问题描述】:

我制作了一个函数(在 JavaScript 中),它从 YouTube 或 Vimeo 获取 URL。它计算出该特定视频的提供者和 ID(演示:http://jsfiddle.net/csjwf/)。

function parseVideoURL(url) {

    var provider = url.match(/http:\/\/(:?www.)?(\w*)/)[2],
        id;

    if(provider == "youtube") {

        id = url.match(/http:\/\/(?:www.)?(\w*).com\/.*v=(\w*)/)[2];
    } else if (provider == "vimeo") {

        id = url.match(/http:\/\/(?:www.)?(\w*).com\/(\d*)/)[2];
    } else {
        throw new Error("parseVideoURL() takes a YouTube or Vimeo URL");    
    }
    return {
        provider : provider,
        id : id
    }
}

它有效,但是作为一个正则表达式新手,我正在寻找改进它的方法。我正在处理的输入通常如下所示:

http://vimeo.com/(id)
http://youtube.com/watch?v=(id)&blahblahblah.....

1) 现在我正在做三个单独的比赛,尝试在一个表达式中完成所有事情是否有意义?如果有,怎么做?

2) 现有的匹配可以更简洁吗?它们是否不必要地复杂?还是不够?

3) 是否存在无法解析的 YouTube 或 Vimeo URL?我已经尝试了很多,到目前为止它似乎工作得很好。

总结一下:我只是在寻找改进上述功能的方法。非常感谢任何建议。

【问题讨论】:

    标签: javascript regex youtube vimeo


    【解决方案1】:

    这是我对正则表达式的尝试,它涵盖了最新的案例:

    function parseVideo(url) {
        // - Supported YouTube URL formats:
        //   - http://www.youtube.com/watch?v=My2FRPA3Gf8
        //   - http://youtu.be/My2FRPA3Gf8
        //   - https://youtube.googleapis.com/v/My2FRPA3Gf8
        // - Supported Vimeo URL formats:
        //   - http://vimeo.com/25451551
        //   - http://player.vimeo.com/video/25451551
        // - Also supports relative URLs:
        //   - //player.vimeo.com/video/25451551
    
        url.match(/(https?\/\/)(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
        var type = null;
        if (RegExp.$3.indexOf('youtu') > -1) {
            type = 'youtube';
        } else if (RegExp.$3.indexOf('vimeo') > -1) {
            type = 'vimeo';
        }
    
        return {
            type: type,
            id: RegExp.$6
        };
    }
    

    【讨论】:

    • 只是一个小改进:(http:\/\/|https:\/\/|) 对于 vimeo.com/12143242 之类的东西
    • @flp 感谢您的建议,已将其纳入。
    【解决方案2】:

    正则表达式非常简洁,但很快就会变得复杂。

    http://jsfiddle.net/8nagx2sk/

    function parseYouTube(str) {
        // link : //youtube.com/watch?v=Bo_deCOd1HU
        // share : //youtu.be/Bo_deCOd1HU
        // embed : //youtube.com/embed/Bo_deCOd1HU
    
        var re = /\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=|embed\/)?([a-z0-9_\-]+)/i; 
        var matches = re.exec(str);
        return matches && matches[1];
    }
    
    function parseVimeo(str) {
        // embed & link: http://vimeo.com/86164897
    
        var re = /\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i;
        var matches = re.exec(str);
        return matches && matches[1];
    }
    

    有时简单的代码对您的开发人员来说更好。

    https://jsfiddle.net/vkg02mhp/1/

    // protocol and www nuetral
    function getVideoId(str, prefixes) {
      const cleaned = str.replace(/^(https?:)?\/\/(www\.)?/, '');
      for(const prefix of prefixes) {
        if (cleaned.startsWith(prefix))
          return cleaned.substr(prefix.length)
      }
      return undefined;
    }
    
    function getYouTubeId(url) {
      return getVideoId(url, [
        'youtube.com/watch?v=',
        'youtu.be/',
        'youtube.com/embed/'
      ]);
    }
    
    function getVimeoId(url) {
      return getVideoId(url, [
        'vimeo.com/'
      ]);
    }
    

    您更喜欢更新哪个?

    【讨论】:

      【解决方案3】:

      我不确定您的问题 3),但是如果您对 url 表单的归纳是正确的,则可以将正则表达式组合成一个,如下所示:

      /http:\/\/(?:www.)?(?:(vimeo).com\/(.*)|(youtube).com\/watch\?v=(.*?)&)/
      

      您将获得不同位置的匹配(如果是 vimeo,则为第 1 和第 2 匹配,如果是 youtube,则为第 3 和第 4 匹配),所以您只需要处理它。

      或者,如果你很确定 vimeo 的 id 只包含数字,那么你可以这样做:

      /http:\/\/(?:www.)?(vimeo|youtube).com\/(?:watch\?v=)?(.*?)(?:\z|&)/
      

      provider 和 id 将分别出现在第 1 场和第 2 场比赛中。

      【讨论】:

      • 查看 stackoverflow.com/a/5831191/208457 了解完整的 YouTube 解析器
      【解决方案4】:

      这是我的正则表达式

      http://jsfiddle.net/csjwf/1/

      【讨论】:

      【解决方案5】:

      对于 Vimeo,不要 依赖 Regex,因为 Vimeo 往往会不时更改/更新其 URL 模式。截至2017 年 10 月 2 日,Vimeo 总共支持六种 URL 方案。

      https://vimeo.com/*
      https://vimeo.com/*/*/video/*
      https://vimeo.com/album/*/video/*
      https://vimeo.com/channels/*/*
      https://vimeo.com/groups/*/videos/*
      https://vimeo.com/ondemand/*/*
      

      改为使用他们的 API 来验证 vimeo URL。这是这个 oEmbed (doc) API,它接受一个 URL,检查其有效性并返回一个包含大量视频信息的对象(查看开发页面)。虽然不是有意的,但我们可以轻松地使用它来验证给定的 URL 是否来自 Vimeo。

      所以,使用 ajax 会是这样的,

      var VIMEO_BASE_URL = "https://vimeo.com/api/oembed.json?url=";
      var yourTestUrl = "https://vimeo.com/23374724";
      
      
      $.ajax({
        url: VIMEO_BASE_URL + yourTestUrl,
        type: 'GET',
        success: function(data) {
          if (data != null && data.video_id > 0)
            // Valid Vimeo url
          else
            // not a valid Vimeo url
        },
        error: function(data) {
          // not a valid Vimeo url
        }
      });
      

      【讨论】:

      • 你能知道这个url是在哪个方案下:https://vimeo.com/334343427/4332adfeb6fall 吗?
      【解决方案6】:

      关于sawa的回答:

      第二个正则表达式的一点更新:

      /http:\/\/(?:www\.)?(vimeo|youtube)\.com\/(?:watch\?v=)?(.*?)(?:\z|$|&)/
      

      (转义点会阻止匹配 www_vimeo_com/... 类型的 url 并添加 $...)

      这里是匹配嵌入网址的相同想法:

      /http:\/\/(?:www\.|player\.)?(vimeo|youtube)\.com\/(?:embed\/|video\/)?(.*?)(?:\z|$|\?)/
      

      【讨论】:

      • 哦!和微小的 URL 形式:/^http:\/\/youtu\.be\/(.+?)(?:|$|\?)/
      • 这个正则表达式不够好,它匹配 http://player.youtube.com/sdfsdfdf 这不是一个有效的 youtube url
      【解决方案7】:

      FWIW,我只是使用以下内容来验证和解析应用中的 YouTube 和 Vimeo URL。我相信您可以添加括号来解析出您要查找的特定内容...

      /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$|^(https?:\/\/)?(www.)?(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*$/
      

      ^^ 这只是使用|(或)连接它们的两个单独表达式的组合。以下分别是原始的 2 个表达式:

      /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/
      
      /^(https?:\/\/)?(www.)?(player.)?vimeo.com\/([a-z]*\/)*([0-9]{6,11})[?]?.*$/
      

      我不是专家,但它似乎根据 Rubular 工作。希望这对将来的人有所帮助。

      【讨论】:

      • 谢谢,我认为最好的正则表达式!
      【解决方案8】:

      3) 您的正则表达式与 https 网址不匹配。我还没有测试过,但我猜“http://”部分会变成“http(s)?://”。请注意,这会改变提供者和 id 的匹配位置。

      【讨论】:

        【解决方案9】:

        以防万一这里是php版本

        /*
        * parseVideo
        * @param (string) $url 
        * mi-ca.ch 27.05.2016
        * parse vimeo & youtube id
        * format url for iframe embed 
        * https://regex101.com/r/lA0fP4/1
        */
        
        function parseVideo($url) {
          $re = "/(http:|https:|)\\/\\/(player.|www.)?(vimeo\\.com|youtu(be\\.com|\\.be|be\\.googleapis\\.com))\\/(video\\/|embed\\/|watch\\?v=|v\\/)?([A-Za-z0-9._%-]*)(\\&\\S+)?/"; 
        preg_match($re, $url, $matches);
        
        if(strrpos($matches[3],'youtu')>-1){
            $type='youtube';
            $src='https://www.youtube.com/embed/'.$matches[6];
        }else if(strrpos($matches[3],'vimeo')>-1){
            $type="vimeo";
            $src='https://player.vimeo.com/video/'.$matches[6];
        }else{
            return false;
        }
        
        
        return array(
                 'type' =>  $type // return youtube or vimeo
                ,'id'   =>  $matches[6] // return the video id
                ,'src'  =>  $src // return the src for iframe embed
                );
        } 
        

        【讨论】:

          【解决方案10】:

          我的任务是启用添加 Dropbox 视频。所以同样的输入应该采用href,检查它并转换为我可以插入的可播放链接。

          const getPlayableUrl = (url) => {
              // Check youtube and vimeo
              let firstCheck = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
          
              if (firstCheck) {
                  if (RegExp.$3.indexOf('youtu') > -1) {
                      return "//www.youtube.com/embed/" + RegExp.$6;
                  } else if (RegExp.$3.indexOf('vimeo') > -1) {
                      return 'https://player.vimeo.com/video/' + RegExp.$6
                  }
              } else {
                  // Check dropbox
                  let candidate = ''
                  if (url.indexOf('.mp4') !== -1) {
                      candidate = url.slice(0, url.indexOf('.mp4') + 4)
                  } else if (url.indexOf('.m4v') !== -1) {
                      candidate = url.slice(0, url.indexOf('.m4v') + 4)
                  } else if (url.indexOf('.webm') !== -1) {
                      candidate = url.slice(0, url.indexOf('.webm') + 5)
                  }
          
                  let secondCheck = candidate.match(/(http:|https:|)\/\/(player.|www.)?(dropbox\.com)\/(s\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*\/)?(.*)/);
                  if (secondCheck) {
                      return 'https://dropbox.com/' + RegExp.$4 + RegExp.$5 + RegExp.$6 + '?raw=1'
                  } else {
                      throw Error("Not supported video resource.");
                  }
              }
          }
          

          【讨论】:

            【解决方案11】:

            我基于之前的答案,但我需要更多的正则表达式。

            也许它在 2011 年有效,但在 2019 年语法发生了一些变化。所以这是一个刷新。

            正则表达式将允许我们检测 url 是 Youtube 或 Vimeo 的天气。 我添加了 Capture 组以轻松检索 videoID。

            如果以不区分大小写的设置运行,请删除 (?i)。

            (?:(?i)(?:https:|http:)?\/\/)?(?:(?i)(?:www\.youtube\.com\/(?:embed\/|watch\?v=)|youtu\.be\/|youtube\.googleapis\.com\/v\/)(?<YoutubeID>[a-z0-9-_]{11,12})|(?:vimeo\.com\/|player\.vimeo\.com\/video\/)(?<VimeoID>[0-9]+))
            

            https://regex101.com/r/PVdjg0/2

            【讨论】:

            • 你的正则表达式是否包含一些函数?
            • @Ugur 你是什么意思正则表达式包含一些功能?如果您的 Regex 实现支持捕获组,您将能够提取 VemoID 或 YoutubeID。 2021 我强烈认为这应该是 2 个正则表达式而不是 1 个。但除此之外。我不知道。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-05
            • 2019-10-25
            • 2011-03-20
            • 2017-12-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多