it-swarm.com.ru

Идентификатор видео на YouTube из URL - Цель C

У меня в основном есть URL-адрес Youtube в качестве NSString, но мне нужно извлечь идентификатор видео, который отображается в URL-адресе. Я нашел много учебников о том, как сделать это на php или других веб-языках программирования, но ни одного в Objective C ...

Я в основном ищу метод, который запрашивает URL-адрес NSString в качестве параметра и возвращает идентификатор видео в качестве еще одной строки nsstring ...

Кто-нибудь знает, как это сделать или какие-нибудь учебники там?

21
The Man

Так что URL YouTube выглядит примерно так: 

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

Идентификатор видео, который вас интересует, - это часть в конце (oHg5SJYRHA0) .... хотя это не обязательно конец, поскольку URL-адреса YouTube могут содержать другие параметры в строке запроса.

Лучше всего использовать регулярное выражение и класс Foundation { NSRegularExpression ). Я бы предположил, что этот подход используется в обучающих программах на других языках, которые вы нашли - обратите внимание, что содержание регулярных выражений почти одинаково в любом языке или инструментарии, который включает их, поэтому любое регулярное выражение, найденное в этих учебниках, должно работать для тебя. (Я бы посоветовал не подходить к использованию v= и использовать ровно 11 символов, так как это подвержено различным способам сбоя, к которым регулярное выражение более устойчиво.)

Чтобы найти идентификатор видео, вам может потребоваться регулярное выражение типа v=([^&]+). v= приводит нас к правой части URL-адреса запроса (в случае, если мы получаем что-то вроде watch?fmt=22&v=oHg5SJYRHA0). Скобки образуют группу capture, поэтому мы можем извлечь только идентификатор видео, а не другие совпадающие символы, которые мы использовали для его поиска, а внутри скобок мы ищем последовательность из одного или нескольких символов, которая не является амперсандом - - это гарантирует, что мы получим все в поле v=whatever, и никаких полей после него, если вы получите URL, такой как watch?v=oHg5SJYRHA0&rel=0.

Используете ли вы это или другое регулярное выражение, вполне вероятно, что вы будете использовать группы захвата. (Если нет, rangeOfFirstMatchInString:options:range: - это почти все, что вам нужно, как видно из ответа Димы.) Вы можете получить содержимое групп захвата (как объекты 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];
}
15
rickster

Вот RegExp это покрыть эти случаи

Цель С

- (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
}
66
Alex

Извините - мне не хватает представителя, чтобы добавить комментарий к выбранному ответу.

Потратив целую вечность, пытаясь найти правильный синтаксис для регулярного выражения, я наткнулся на это, которое мне помогло. Надеюсь, это может помочь кому-то еще!

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

Взято из здесь . Это работает для следующих форматов URL:

38
jt_uk

Обучающие программы, которые вы, вероятно, видите, являются просто инструкциями по использованию регулярных выражений, что также является тем, что вы хотите использовать в этом случае.

Класс Какао, который вам нужно будет использовать, это 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;
}
9
Dima

Вам даже не нужны регулярные выражения. Следующее работает независимо от длины идентификатора видео и его позиции в 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);
7
user529758

Основываясь на этом ответе: PHP Regex, чтобы получить идентификатор видео YouTube?

Я адаптировал регулярное выражение для строки 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;
}

Матчи:

Не совпадает:

3
João Nunes
- (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;
}
2
user2839919

Я использовал ответ с наибольшим количеством голосов, чтобы написать лучшее, более ограничительное регулярное выражение.

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];
2
skensell

Объединяя некоторые из ваших ответов, я бы сказал, что это лучший ответ:

+ (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;
}
1
jomafer

Обновление Swift 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's 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)
}
1
ElegyD

Здесь есть много хороших ответов, но я подумал, что некоторым было бы полезно проанализировать несколько 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 для Regex

1
Joe Barbour

Вот мое решение, которое ссылается на StackOverFlow. ( Youtube I.D парсинг для новых форматов URL )

Я сделал некоторые изменения. 

/// Это .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
1
Prophecy

Swift 2 версия для @Alex ответа

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
}
1
Sunil Sharma

Swift 3 версия для @Alex ответа

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
}
0
ddnl

Вот версия Swift с использованием регулярного выражения @ 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 ""
    }
}
0
benaneesh