23

我有一个 Youtube url 作为 an NSStringor Swift String,但我需要提取显示在 url 中的视频 ID。我找到了许多关于如何在 php 或其他基于 Web 的编程语言中执行此操作的教程,但在 Apple 平台的 Objective-C 或 Swift 中没有找到...

我正在寻找一种要求 NSString url 作为参数并将视频 ID 作为另一个 NSString 返回的方法...

4

17 回答 17

70

这是 RegExp 它涵盖了这些情况

目标 C

- (NSString *)extractYoutubeIdFromLink:(NSString *)link {
    NSString *regexString = @"((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)";
    NSRegularExpression *regExp = [NSRegularExpression regularExpressionWithPattern:regexString
                                                                            options:NSRegularExpressionCaseInsensitive
                                                                              error:nil];

    NSArray *array = [regExp matchesInString:link options:0 range:NSMakeRange(0,link.length)];
    if (array.count > 0) {
        NSTextCheckingResult *result = array.firstObject;
        return [link substringWithRange:result.range];
    }
    return nil;
}

迅速

func extractYoutubeIdFromLink(link: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let regExp = try? NSRegularExpression(pattern: pattern, options: .CaseInsensitive) else {
        return nil
    }
    let nsLink = link as NSString
    let options = NSMatchingOptions(rawValue: 0)
    let range = NSRange(location: 0,length: nsLink.length)
    let matches = regExp.matchesInString(link as String, options:options, range:range)
    if let firstMatch = matches.first {
        return nsLink.substringWithRange(firstMatch.range)
    }
    return nil
}

斯威夫特 3

func extractYoutubeIdFromLink(link: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let regExp = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
        return nil
    }
    let nsLink = link as NSString
    let options = NSRegularExpression.MatchingOptions(rawValue: 0)
    let range = NSRange(location: 0, length: nsLink.length)
    let matches = regExp.matches(in: link as String, options:options, range:range)
    if let firstMatch = matches.first {
        return nsLink.substring(with: firstMatch.range)
    }
    return nil
}
于 2015-01-06T10:06:01.550 回答
39

在花了很长时间试图找到正则表达式的正确语法之后,我遇到了这个对我有帮助的东西。

NSString *regexString = @"(?<=v(=|/))([-a-zA-Z0-9_]+)|(?<=youtu.be/)([-a-zA-Z0-9_]+)";

取自这里。这适用于以下 URL 格式:

 - www.youtube.com/v/VIDEOID  
 - www.youtube.com?v=VIDEOID
 - http://www.youtube.com/watch?v=KFPtWedl7wg&feature=youtu.be
 - http://www.youtube.com/watch?v=MkTD2Y4LXcM 
 - youtu.be/KFPtWedl7wg_U923
 - http://www.youtube.com/watch?feature=player_detailpage&v=biVLGTAMC_U#t=31s
于 2013-01-02T20:56:29.183 回答
15

所以一个 YouTube URL 看起来像这样:

http://www.youtube.com/watch?v=oHg5SJYRHA0

您感兴趣的视频 ID 是末尾部分 ( oHg5SJYRHA0).... 虽然不一定在末尾,因为 YouTube URL 可以在查询字符串中包含其他参数。

您最好的选择可能是使用正则表达式和 Foundation 的NSRegularExpression类。我认为这种方法已在您找到的其他语言教程中使用 - 请注意,正则表达式的内容在任何包含它们的语言或工具包中都几乎相同,因此在这些教程中找到的任何正则表达式都应该工作为你。(我建议您不要使用v=11 个字符的方法,因为这很容易导致正则表达式更健壮的各种失败模式。)

要查找视频 ID,您可能需要像v=([^&]+). 将v=我们带到查询 URL 的正确部分(如果我们得到类似的东西watch?fmt=22&v=oHg5SJYRHA0)。括号构成一个捕获组,因此我们可以仅提取视频 ID 而不是我们用来查找它的其他匹配字符,并且在括号内我们查找一个或多个不是 & 字符的序列 - 这确保我们会在该v=whatever字段中获取所有内容,如果您获得类似watch?v=oHg5SJYRHA0&rel=0.

无论您使用此正则表达式还是其他正则表达式,您都可能会使用捕获组。(如果没有,rangeOfFirstMatchInString:options:range:这几乎就是您所需要的,如 Dima 的回答所示。)您可以使用或类似方法获取捕获组(作为NSTextCheckingResult对象)的内容:firstMatchInString:options:range:

NSError *error = NULL;
NSRegularExpression *regex = 
[NSRegularExpression regularExpressionWithPattern:@"?.*v=([^&]+)"
                                          options:NSRegularExpressionCaseInsensitive
                                            error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:youtubeURL
                                                options:0
                                                  range:NSMakeRange(0, [youtubeURL length])];
if (match) {
    NSRange videoIDRange = [match rangeAtIndex:1];
    NSString *substringForFirstMatch = [youtubeURL substringWithRange:videoIDRange];
}
于 2012-07-16T18:14:08.157 回答
9

您可能看到的教程只是关于如何使用正则表达式的说明,这也是您在这种情况下要使用的内容。

您需要使用的 Cocoa 类是NSRegularExpression

您的实际正则表达式字符串将取决于您期望 url 采用的格式,因为它看起来像 youtube 有几个。一般功能将如下所示:

+ (NSString *)extractYoutubeID:(NSString *)youtubeURL
{
  NSError *error = NULL;  
  NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"your regex string goes here" options:NSRegularExpressionCaseInsensitive error:&error];
  NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:youtubeURL options:0 range:NSMakeRange(0, [youtubeURL length])];
  if(!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0)))
  {
    NSString *substringForFirstMatch = [youtubeURL substringWithRange:rangeOfFirstMatch];

    return substringForFirstMatch;
  }
  return nil;
}
于 2012-07-16T17:51:14.863 回答
7

你甚至不需要正则表达式。无论视频 ID 的长度及其在 URL 中的位置如何,以下操作均有效:

NSString *vID = nil;
NSString *url = @"http://www.youtube.com/watch?v=cAcqdjLCN7s";

NSString *query = [url componentsSeparatedByString:@"?"][1];
NSArray *pairs = [query componentsSeparatedByString:@"&"];
for (NSString *pair in pairs) {
    NSArray *kv = [pair componentsSeparatedByString:@"="];
    if ([kv[0] isEqualToString:@"v"]) {
        vID = kv[1];
        break;
    }
}

NSLog(@"%@", vID);
于 2013-07-22T22:12:03.947 回答
3

基于这个答案:PHP Regex to get youtube video ID?

我为 c/objc/c++ 字符串改编了一个正则表达式,这里的重要部分是正则表达式不会从 facebook 或其他服务获取视频。iOS 正则表达式基于:ICU

NSString *regexString = @"^(?:http(?:s)?://)?(?:www\\.)?(?:m\\.)?(?:youtu\\.be/|youtube\\.com/(?:(?:watch)?\\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)/))([^\?&\"'>]+)";

NSError *error;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:regexString
                                          options:NSRegularExpressionCaseInsensitive
                                            error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:message
                                                options:0
                                                  range:NSMakeRange(0, [message length])];

if (match && match.numberOfRanges == 2) {
    NSRange videoIDRange = [match rangeAtIndex:1];
    NSString *videoID = [message substringWithRange:videoIDRange];
    
    return videoID;
}

火柴:

- youtube.com/v/vidid
- youtube.com/vi/vidid
- youtube.com/?v=vidid
- youtube.com/?vi=vidid
- youtube.com/watch?v=vidid
- youtube.com/watch?vi=vidid
- youtu.be/vidid
- youtube.com/embed/vidid
- http://youtube.com/v/vidid
- http://www.youtube.com/v/vidid
- https://www.youtube.com/v/vidid
- youtube.com/watch?v=vidid&wtv=wtv
- http://www.youtube.com/watch?dev=inprogress&v=vidid&feature=related
- https://m.youtube.com/watch?v=vidid

不匹配:

- www.facebook.com?wtv=youtube.com/v/vidid
- https://www.facebook.com/video.php?v=10155279523025107
于 2015-01-14T11:27:44.293 回答
2
- (NSString*)getYoutubeVideoID:(NSString*)url {
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=watch\\?v=|/videos/|embed\\/)[^#\\&\\?]*"
                                              options:NSRegularExpressionCaseInsensitive
                                                error:&error];

    NSTextCheckingResult *match = [regex firstMatchInString:url
                                                    options:0
                                                      range:NSMakeRange(0, [url length])];
    NSString *substringForFirstMatch;
    if (match) {
        NSRange videoIDRange = [match rangeAtIndex:0];
        substringForFirstMatch = [url substringWithRange:videoIDRange];
    }
    return substringForFirstMatch;
}
于 2013-10-04T07:33:08.743 回答
2

我使用投票最高的答案来编写更好、更严格的正则表达式。

NSString *regex = @"(?:youtube.com.+v[=/]|youtu.be/)([-a-zA-Z0-9_]+)";

然后你就可以拿到身份证了

NSTextCheckingResult *match = [regex firstMatchInString:url
                                                options:0
                                                  range:NSMakeRange(0, [url length])];
NSRange videoIDRange = [match rangeAtIndex:1];
NSString *youTubeID = [url substringWithRange:videoIDRange];
于 2014-02-28T06:45:24.383 回答
1

这是我从 StackOveFlow 引用的解决方案。(新 URL 格式的 Youtube ID 解析

我做了一些修改。

///这是.h

#import <Foundation/Foundation.h>
@interface YoutubeParser : NSObject

+(BOOL) isValidateYoutubeURL:(NSString * )youtubeURL;

+(NSArray *) parseHTML:(NSString *)html ;

@end

///This is the .m 
#import "YoutubeParser.h"

@interface YoutubeParser () {
}

@end

@implementation YoutubeParser

#define YOUTUBE_PATTERN @"(https?://)?(www\\.)?(youtu\\.be/|youtube\\.com)?(/|/embed/|/v/|/watch\\?v=|/watch\\?.+&v=)([\\w_-]{11})(&.+)?"

+(NSRegularExpression *)regex {

    static NSRegularExpression * regex = nil;

    regex =     [NSRegularExpression regularExpressionWithPattern:YOUTUBE_PATTERN
                                                               options:NSRegularExpressionCaseInsensitive
                                                                 error:nil];
    return regex;
}

+(BOOL) isValidateYoutubeURL:(NSString * )youtubeURL {
    NSInteger cnt = [[YoutubeParser regex] numberOfMatchesInString:youtubeURL options:0 range:NSMakeRange(0, [youtubeURL length])  ];

    return cnt > 0 ? YES : NO;
}

typedef void (^matching_block_t)  (NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop);

+(NSArray *) parseHTML:(NSString *)html {
    NSMutableArray * youtubeURLArray = [[NSMutableArray alloc] init];

    matching_block_t parseTask = ^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        NSRange matchRange = [result range];
        NSRange youtubeKey = [result rangeAtIndex:5]; //the youtube key
        NSString * strKey = [html substringWithRange:youtubeKey] ;
        NSLog(@"youtubeKey=%@ , with url=%@ " ,strKey , [html substringWithRange:matchRange]);

        [youtubeURLArray addObject:strKey];
    };

    [[YoutubeParser regex] enumerateMatchesInString:html   options:0   range:NSMakeRange(0, [html length])   usingBlock:parseTask ];

    return youtubeURLArray;
}

@end
于 2013-07-22T22:05:56.320 回答
1

这里有很多很好的答案,但我认为从字符串中解析多个video_ID可能对某些人有益。这可能是一个网页或一组不同的 URL。

页面内容示例

NSString *content = @"http://www.youtube.com/user/Scobleizer#p/u/1/1p3vcRhsYGo,http://youtu.be/NLqAF9hrVbY,http://www.youtube.com/watch?v=NLqAF9hrVbY,http://facebook.com,http://www.youtube.com/watch?v=cAcqdjLCN7s";

方法

-(NSArray *)extractVideos:(NSString *)content {
    NSString *extractRegex = @"(?<=v(=|/))([-a-zA-Z0-9_]+)|(?<=youtu.be/)([-a-zA-Z0-9_]+)"
    NSMutableArray *extractedContent = [[NSMutableArray alloc] init];
    if ([content hasPrefix:@"http://"] || [content hasPrefix:@"https://"]) {
        NSURL *extractURL = [NSURL URLWithString:content];
        if ([extractURL.host rangeOfString:@"youtu"].location != NSNotFound) {
            NSRegularExpression *extractRegex = [NSRegularExpression regularExpressionWithPattern:extractRegex options:NSRegularExpressionCaseInsensitive error:nil];
            NSArray *extractResults = [extractRegex matchesInString:content options:0 range:NSMakeRange(0, content.length)];
            for (NSTextCheckingResult *match in extractResults) {
                [extractedContent addObject:[content substringWithRange:match.range]];

            }

        }

    }

    return extractedContent;

}

输出

( 
    NLqAF9hrVbY,
    QLqAF9eeVbY,
    cAcqdjLCN7s
)

归功于 @Alex 的正则表达式

于 2015-04-11T04:08:59.960 回答
1

合并您的一些答案,我会说这是最好的答案:

+ (NSString *)extractYoutubeID:(NSString *)youtubeURL
{
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?<=v(=|/))([-a-zA-Z0-9_]+)|(?<=youtu.be/)([-a-zA-Z0-9_]+)"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];
    NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:youtubeURL options:NSMatchingReportProgress range:NSMakeRange(0, [youtubeURL length])];
    if(rangeOfFirstMatch.location != NSNotFound) {
        NSString *substringForFirstMatch = [youtubeURL substringWithRange:rangeOfFirstMatch];

        return substringForFirstMatch;
    }

    return nil;
}
于 2015-11-11T11:35:23.547 回答
1

@Alex 答案的Swift 2版本

func getYoutubeVideoId(youtubeLink:String) -> String?{
    var youtubeId:String? = nil
    let pattern: String = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    do {
        let regex = try NSRegularExpression(pattern: pattern, options: .CaseInsensitive)
        if let regexMatch = regex.firstMatchInString(youtubeLink, options: NSMatchingOptions(rawValue: 0), range: NSRange(location: 0, length: youtubeLink.characters.count)) {
            youtubeId = (youtubeLink as NSString).substringWithRange(regexMatch.range)
        }
    }
    catch let error as NSError{
        print("Error while extracting youtube id \(error.debugDescription)")
    }

    return youtubeId
}
于 2016-05-25T10:10:57.233 回答
1

更新斯威夫特 4:

static func extractYoutubeVideoId(from url: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let range = url.range(of: pattern, options: .regularExpression) else { return nil }
    return String(url[range])
}

旧答案:
@Alex 的 Swift 3 答案更快捷,不使用 NSString:
我们可以强制尝试正则表达式,因为我们知道它是有效的。

static func extractYoutubeVideoId(from url: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    let regex = try! NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
    let range = NSRange(location: 0, length: url.utf16.count)
    guard let firstMatch = regex.firstMatch(in: url, options: .init(rawValue: 0), range: range) else { return nil }
    let start = String.UTF16Index(firstMatch.range.location)
    let end = String.UTF16Index(firstMatch.range.location + firstMatch.range.length)
    return String(url.utf16[start..<end])
}

或者,如果你仍然想要 NSString:

static func extractYoutubeVideoId(from url: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    let regex = try! NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
    let range = NSRange(location: 0, length: (url as NSString).length)
    guard let firstMatch = regex.firstMatch(in: url, options: .init(rawValue: 0), range: range) else { return nil }
    return (url as NSString).substring(with: firstMatch.range)
}
于 2017-04-04T12:14:46.817 回答
0

这是使用@jt_ik 正则表达式的快速版本:

func extractYoutubeID(youtubeURL: String) -> String {
    var error: NSError?
    let pattern: String = "(?<=v(=|/))([-a-zA-Z0-9_]+)|(?<=youtu.be/)([-a-zA-Z0-9_]+)"
    let regex = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)!

    if error == nil {
        if let regexMatch = regex.firstMatchInString(youtubeURL, options: nil, range: NSRange(location: 0, length: youtubeURL.utf16Count)) {
            return (youtubeURL as NSString).substringWithRange(regexMatch.range)
        }
        // Handle no match here
        return ""
    } else {
        // Handle error here
        println(error?.userInfo)
        return ""
    }
}
于 2015-01-14T18:59:27.730 回答
0

@Alex 答案的Swift 3版本

func extractYoutubeIdFromLink(link: String) -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/))([\\w-]++)"
    guard let regExp = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) else {
        return nil
    }
    let nsLink = link as NSString
    let options = NSRegularExpression.MatchingOptions(rawValue: 0)
    let range = NSRange(location: 0,length: nsLink.length)
    let matches = regExp.matches(in: link as String, options:options, range:range)
    if let firstMatch = matches.first {
        debugPrint(firstMatch)
        return nsLink.substring(with: firstMatch.range)
    }
    return nil
}
于 2017-03-08T16:29:31.533 回答
0

斯威夫特 5

这是我正在使用的最新工作版本。我还添加了对 YouTube 短视频的支持。前任:https://youtube.com/shorts/2xL2WlQM7Nc

extension String{
  func extractYoutubeId() -> String? {
    let pattern = "((?<=(v|V)/)|(?<=be/)|(?<=(\\?|\\&)v=)|(?<=embed/)|(?<=shorts/))([\\w-]++)"
    if let matchRange = self.range(of: pattern, options: .regularExpression) {
        return String(self[matchRange])
    } else {
        return .none
    }
  }
}

例子:

let ytShortVideoLink = "https://youtube.com/shorts/2xL2WlQM7Nc"
print("Video ID:",ytShortVideoLink. extractYoutubeId())
//Output: 
Video ID: 2xL2WlQM7Nc
于 2021-07-31T05:27:08.127 回答
-2

我自己想通了...

NSArray *videoURLSplit = [videoURL componentsSeparatedByString:@"v="];
NSString *videoID = [[videoURLSplit objectAtIndex:1] substringToIndex:11];
NSLog(@"%@",videoID);

非常简单...所有视频 url 都包含 v=VIDEO_ID 我只是将 url 分成一个数组,然后取 v= 之后的前 11 位数字,因为 url 中可能有更多 http GET 信息...

感谢您的帮助!

于 2012-07-16T18:02:38.630 回答