Можно ли обнаружить ссылки в NSString, которые имеют пробелы в них с NSDataDetector?

Во-первых, я не контролирую текст, который получаю. Просто хотел показать это, чтобы вы знали, что я не могу изменить ссылки.

Текст, который я пытаюсь найти, используя ссылки NSDataDetector содержит следующее:

<h1>My main item</h1>
<img src="http://www.blah.com/My First Image Here.jpg">
<h2>Some extra data</h2>

Вот код обнаружения, который я использую, но он не найдет эту ссылку:

NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];

for (NSTextCheckingResult *match in matches) 
{
   if ([match resultType] == NSTextCheckingTypeLink)
   {
      NSURL *url = [match URL];
      // does some stuff
   }
}

Это ошибка с обнаружением ссылок Apple, когда она не может обнаружить ссылки с пробелами, или я делаю что-то не так?

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

8 ответов

Я только что получил этот ответ от Apple за ошибку, которую я подал на это:

Мы считаем, что эта проблема была решена в последней бета-версии iOS 9. Это предварительное обновление iOS 9.

Пожалуйста, обратитесь к примечаниям к выпуску для получения полной инструкции по установке.

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

iOS 9 https://developer.apple.com/ios/download/

Я протестирую и сообщу всем, исправлено ли это в iOS 9.

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

// assume str = <img src="http://www.blah.com/My First Image Here.jpg">
NSArray *components = [str componentsSeparatedByString:@" "];
for (NSString *strWithNoSpace in components) {
    // feed strings into data detector
}

Другой альтернативой является поиск именно этого HTML-тега. Это менее общее решение.

// assume that those 3 HTML strings are in a string array called strArray
for (NSString *htmlLine in strArray) {
    if ([[htmlLine substringWithRange:NSMakeRange(0, 8)] isEqualToString:@"<img src"]) {
        // Get the url from the img src tag
        NSString *urlString = [htmlLine substringWithRange:NSMakeRange(10, htmlLine.length - 12)];
    }
}

Попробуйте этот фрагмент (я получил регулярное выражение от вашего первого комментатора user3584460):

NSError *error = NULL;
NSString *myHTML = @"<http><h1>My main item</h1><img src=\"http://www.blah.com/My First Image Here.jpg\"><h2>Some extra data</h2><img src=\"http://www.bloh.com/My Second Image Here.jpg\"><h3>Some extra data</h3><img src=\"http://www.bluh.com/My Third-Image Here.jpg\"></http>";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"src=[\"'](.+?)[\"'].*?>" options:NSRegularExpressionCaseInsensitive error:&error];

NSArray *arrayOfAllMatches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];

NSTextCheckingResult *match = [regex firstMatchInString:myHTML options:0 range:NSMakeRange(0, myHTML.length)];



for (NSTextCheckingResult *match in arrayOfAllMatches) {
    NSRange  range = [match rangeAtIndex:1];

    NSString* substringForMatch = [myHTML substringWithRange:range];
    NSLog(@"Extracted URL : %@",substringForMatch);

}

В моем журнале у меня есть:

Extracted URL  : http://www.blah.com/My First Image Here.jpg
Extracted URL  : http://www.bloh.com/My Second Image Here.jpg
Extracted URL  : http://www.bluh.com/My Third-Image Here.jpg

Попробуйте этот шаблон регулярных выражений: @"<img[^>]+src=(\"|')([^\"']+)(\"|')[^>]*>" с игнорированием регистра... Соответствие index=2 для исходного URL.

regex demo в javascript: (попробуйте любую помощь)

демонстрация

Ты можешь использовать NSRegularExpression исправить все URL с помощью простого регулярного выражения для обнаружения ссылок, а затем просто кодировать пробелы (если вам нужно более сложное кодирование, вы можете посмотреть в CFURLCreateStringByAddingPercentEscapes и есть много примеров там). Единственное, что может занять у вас время, если вы не работали с NSRegularExpression Прежде чем выполнить итерацию результатов и выполнить замену, следующий код должен помочь:

NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"src=\".*\"" options:NSRegularExpressionCaseInsensitive error:&error];
if (!error)
{
    NSInteger offset = 0;
    NSArray *matches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
    for (NSTextCheckingResult *result in matches)
    {
        NSRange resultRange = [result range];
        resultRange.location += offset;

        NSString *match = [regex replacementStringForResult:result inString:myHTML offset:offset template:@"$0"];
        NSString *replacement = [match stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

        myHTML = [myHTML  stringByReplacingCharactersInRange:resultRange withString:replacement];
        offset += ([replacement length] - resultRange.length);
    }
}

Я нашел очень хакерский способ решить мою проблему. Если кто-то придумает лучшее решение, которое можно применить ко всем URL-адресам, сделайте это.

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

По сути, я разбил строку на компоненты, основанные на них, начиная с "http:// в массив. Затем я перебираю этот массив, выполняя очередной поиск .jpg">, Счетчик внутреннего массива будет только > 1 когда .jpg"> Строка найдена. Затем я сохраняю и строку, которую нахожу, и строку, которую я исправляю %20 замены, и используйте их для окончательной замены исходной строки.

Это не идеально и, вероятно, неэффективно, но оно выполняет работу для того, что мне нужно.

- (NSString *)replaceSpacesInJpegURLs:(NSString *)htmlString
{
    NSString *newString = htmlString;

    NSArray *array = [htmlString componentsSeparatedByString:@"\"http://"];
    for (NSString *str in array)
    {
        NSArray *array2 = [str componentsSeparatedByString:@".jpg\""];

        if ([array2 count] > 1)
        {
            NSString *stringToFix = [array2 objectAtIndex:0];
            NSString *fixedString = [stringToFix stringByReplacingOccurrencesOfString:@" " withString:@"%20"];

            newString = [newString stringByReplacingOccurrencesOfString:stringToFix withString:fixedString];
        }
    }

    return newString;
}

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

Если вашей строкой является HTML, вам следует использовать библиотеку HTML для разбора. Есть несколько наборов с открытым исходным кодом, чтобы помочь вам сделать это. Затем просто возьмите атрибуты href ваших якорей или запустите NSDataDetector на текстовых узлах, чтобы найти вещи, не размеченные, без загрязнения строки тегами.

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

// Custom function which cleans up strings ready to be used for URLs
func cleanStringForURL(string: NSString) -> NSString {
    var temp = string
    var clean = string.stringByReplacingOccurrencesOfString(" ", withString: "")
    return clean
}
Другие вопросы по тегам