Search code examples
iosobjective-cnsattributedstringnsrange

iOS: resize images in html attributed string


I have a attributed string which is decoded from html code

NSAttributedString *htmlstring =[[NSAttributedString alloc] initWithData:[formatString dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                                                                                                                              NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}documentAttributes:nil error:&error];

And in the string I have multiple img tags like

...
<p style="text-align: left;">
<img src="http://139.196.32.98/ueditor/php/upload/image/20160408/1460107835846711.jpg" alt="1460107835846711.jpg" width="75" height="103" style="width: 75px; height: 103px;"/>
<img src="http://139.196.32.98/ueditor/php/upload/image/20160408/1460106959338375.jpg" alt="1460106959338375.jpg" width="359" height="445" style="width: 359px; height: 445px;"/></p>
...

Now I have to resize the image in order to fix the mobile screen. And I tried

 NSString* substring = @"<img";
 NSRange range = [htmlstring rangeOfString:substring];

but it only returns the first search result, and how to make the whole tag into a substring?

Thank you so much


Solution

  • In order to continue searching past first occurrence, you need to adjust the range you perform your search in. There's a method on NSString that allows you do just that:

    - [NSString rangeOfString:options:range:];
    

    So you need to go beneath NSAttributedString and work with its plain-text representation which can be accessed via its read-only string property.

    So the idea is to calculate a new search range every time a match is found:

    NSString *substring = @"<img";
    NSString *plainString = [htmlstring string];
    NSRange searchRange = NSMakeRange(0, [plainString length]);
    NSRange openingTagRange = [plainString rangeOfString:substring options:0 range:searchRange];
    while  ( openingTagRange.location < [plainString length] )
    {
        NSLog(@"found opening tag at %lu", (unsigned long)openingTagRange.location);
        searchRange.location = NSMaxRange(openingTagRange);
        searchRange.length = [plainString length] - NSMaxRange(openingTagRange);
        openingTagRange = [plainString rangeOfString:openingTagString options:0 range:searchRange];
    }
    

    If you also want to make the whole tag into a substring, the while loop expands into the following:

    while  ( openingTagRange.location < [plainString length] )
    {
        searchRange.location = NSMaxRange(openingTagRange);
        searchRange.length = [plainString length] - NSMaxRange(openingTagRange);
        NSRange closingTagRange = [plainString rangeOfString:@">" options:0 range:searchRange];
    
        if (closingTagRange.location > [plainString length])
        {
            break;
        }
    
        NSRange wholeTagRange = NSMakeRange(openingTagRange.location, NSMaxRange(closingTagRange) - openingTagRange.location);
        NSString *wholeTagString = [plainString substringWithRange:wholeTagRange];
        NSLog(@"wholeTagString == %@", wholeTagString);
        searchRange.location = NSMaxRange(wholeTagRange);
        searchRange.length = [plainString length] - NSMaxRange(wholeTagRange);
        openingTagRange = [plainString rangeOfString:substring options:0 range:searchRange];
    }
    

    Note, that the first closing bracket encountered is assumed to close the tag, which, I guess, might not always be the case.