2015-09-02 90 views
2

我使用此代碼使用RegEx將HTML字符串轉換爲NSAttributedString。我遇到的唯一問題是嵌套粗體和斜體標籤。 RegEx是正確的方法嗎?將嵌套粗斜體HTML標記轉換爲NSAttributedString

另外我想避免使用HTML解析器,因爲我需要的全部是粗體,斜體和下劃線屬性,並且如果可能,請使用StrikeThrough。

有什麼建議嗎?

- (NSMutableAttributedString *)applyStylesToString:(NSString *)string searchRange:(NSRange)searchRange { 

    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string]; 
    [attributedString addAttribute:NSFontAttributeName value:[StylesConfig regularLargeFont] range:searchRange]; 

    NSDictionary *boldAttributes = @{ NSFontAttributeName : [StylesConfig regularBoldLargeFont] }; 
    NSDictionary *italicAttributes = @{ NSFontAttributeName : [StylesConfig regularItalicLargeFont] }; 
    NSDictionary *underlineAttributes = @{ NSUnderlineStyleAttributeName : @1}; 
    NSDictionary *strikeThroughAttributes = @{ NSStrikethroughStyleAttributeName : @1}; 

    NSDictionary *replacements = @{ 
            @"<b>(.*?)</b>" : boldAttributes, 
            @"<i>(.*?)</i>" : italicAttributes, 
            @"<u>(.*?)</u>" : underlineAttributes, 
            @"<s>(.*?)</s>" : strikeThroughAttributes 
            }; 

    for (NSString *key in replacements) { 

     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:key options:0 error:nil]; 

     [regex enumerateMatchesInString:string options:0 range:searchRange usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){ 
      NSRange matchRange = [match rangeAtIndex:1]; 

      [attributedString addAttributes:replacements[key] range:matchRange]; 

      if ([key isEqualToString:@"<b>(.*?)</b>"]) { 
       [self makeBoldItalic:attributedString matchRange:matchRange font:@"SourceSansPro-It"]; 

      } else if ([key isEqualToString:@"<i>(.*?)</i>"]) { 
       [self makeBoldItalic:attributedString matchRange:matchRange font:@"SourceSansPro-Semibold"]; 
      } 
     }]; 
    } 
    [[attributedString mutableString] replaceOccurrencesOfString:@"<b>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"</b>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"<i>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"</i>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"<u>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"</u>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"<s>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 
    [[attributedString mutableString] replaceOccurrencesOfString:@"</s>" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, attributedString.length)]; 

    return attributedString; 
} 

- (void)makeBoldItalic:(NSMutableAttributedString *)attributedString matchRange:(NSRange)matchRange font:(NSString *)font { 

    [attributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { 

     UIFont *oldFont = (UIFont *)value; 
     if ([oldFont.fontName isEqualToString:font]) { 

      [attributedString removeAttribute:NSFontAttributeName range:range]; 
      NSDictionary *boldItalicAttributes = @{ NSFontAttributeName : [StylesConfig regularBoldItalicLargeFont] }; 
      [attributedString addAttributes:boldItalicAttributes range:matchRange]; 
     } 
    }]; 
} 
+1

什麼樣的嵌套標籤導致您問題?你有一個不正確的例子嗎? – Larme

+0

「這是斜體和大膽文本」 - >這不工作,而這個人做 - >「這是斜體和大膽文本」 –

+1

我想你的代碼與你的兩個NSString的測試。它通過了。我所做的最大的不同之處在於,不是改變字體,而是將'NSBackgroundColorAttributeName'設置爲粗體,將'NSForegroundColorAttributeName'設爲斜體。有效。我猜你的字體測試是錯誤的。如果您還沒有應用粗體字體,我不知道它應該如何應用斜體字體。 – Larme

回答

4

事情是粗體和斜體(和其他屬性)是字體的一部分,不像下劃線。例如,iOS不會像Photoshop那樣提供「假大膽」或「假斜體」。 boldFontitalicFontboldItalicFont

所以,我從你有你的StylesConfig類公用事業猜測。

boldFont = [StylesConfig regularBoldLargeFont]; //SourceSansPro-Semibold 
italicFont = [StylesConfig regularItalicLargeFont];//SourceSansPro-It 
boldItalicFont = [StylesConfig regularBoldItalicLargeFont];//SourceSansPro-SemiboldIt (or something like this) 

所以要更改字體,希望在其symbolicTraitsfontDescriptor字體包含正確的,你可以做這樣的事情:

-(void)boldText:(NSMutableAttributedText *)attributeString forRange:(NSRange)range 
{ 
    [attributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { 
    UIFont *currentFont = (UIFont *)value; 
    if ([[currentFont fontDescriptor] symbolicTraits] & UIFontDescriptorTraitBold) 
    { 
     NSLog(@"Font is already bold); 
    } 
    else 
    { 
     UIFont *newFont = [self boldFontFromFont:currentFont]; 
     [attributedString addAttribute:newFont range:range]; 
    } 
    }]; 
} 

-(void)italicText:(NSMutableAttributedText *)attributeString forRange:(NSRange)range 
{ 
    [attributedString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, attributedString.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { 
    UIFont *currentFont = (UIFont *)value; 
    if ([[currentFont fontDescriptor] symbolicTraits] & UIFontDescriptorTraitItalic) 
    { 
     NSLog(@"Font is already italic); 
    } 
    else 
    { 
     UIFont *newFont = [self italicFontFromFont:currentFont]; 
     [attributedString addAttribute:newFont range:range]; 
    } 
    }]; 
} 

-(UIFont *)boldFontFromFont:(UIFont *)font 
{ 
    if ([[currentFont fontDescriptor] symbolicTraits] & UIFontDescriptorTraitItalic) 
     return boldItalicFont; 
    else 
     return boldFont; 
} 

-(UIFont *)italicFontFromFont:(UIFont *)font 
{ 
    if ([[currentFont fontDescriptor] symbolicTraits] & UIFontDescriptorTraitBold) 
     return boldItalicFont; 
    else 
     return italicFont; 
} 

在你當前的代碼:

if ([key isEqualToString:@"<b>(.*?)</b>"]) 
{ 
    [self boldText: attributedString forRange:matchRange]; 
} 
else if ([key isEqualToString:@"<i>(.*?)</i>"]) 
{ 
    [self italicText: attributedString forRange:matchRange]; 
} 

如果您的字體未通過symbolicTraits測試,您可能需要查看UIFontfontName並檢查i其粗體,斜體或粗體。

注:
我沒有測試的代碼,我寫它只有在這裏,我甚至不知道是否編譯,但應該給你的整體思路。

+0

它工作!非常感謝! –

+0

你是什麼意思關於你的「StylesConfig類」?我應該上那門課嗎? – ePascoal

+0

@MrMartin:不一定。從作者代碼看,「StylesConfig」似乎是一個單身人士或同化者,只是提供了從任何地方都可訪問的UIFont。 – Larme