I basically have a Youtube url as an NSString, but I need to extract the video id that is displayed in the url. I found many tutorials on how to do this in php or and other
Here is my solution which referenced from StackOveFlow. (Youtube I.D parsing for new URL formats)
I did some modification.
///This is the .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
Based on this answer: PHP Regex to get youtube video ID?
I adapted a regex for c/objc/c++ string, the important part here is that the regex doesn't get videos from facebook or other services. iOS regex is based on: 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;
}
Matches:
Does not match:
There is a lot of good answers here but I thought it might be beneficial to some to parse multiple video_ID from a string. This could be a web page or an array of different URL.
Example of page content
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";
Method
-(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;
}
Output
(
NLqAF9hrVbY,
QLqAF9eeVbY,
cAcqdjLCN7s
)
Credit to @Alex for the Regex
You don't even need regexes. The following works regardless of the length of the video ID and its position within the 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);
I figured it out by myself...
NSArray *videoURLSplit = [videoURL componentsSeparatedByString:@"v="];
NSString *videoID = [[videoURLSplit objectAtIndex:1] substringToIndex:11];
NSLog(@"%@",videoID);
Very simple... All video urls contain v=VIDEO_ID I just separated the url into an array and then took the first 11 digits of what is after v= since there could be more http GET information in the url...
Thanks for helping though!
Here is RegExp it cover these cases
Objective 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;
}
Swift
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
}
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 {
return nsLink.substring(with: firstMatch.range)
}
return nil
}