使用Swift中的NSRegularExpression对特定范围内的单词进行属性

时间:2017-01-19 15:39:04

标签: ios regex swift nsattributedstring nsrange

我有一些纯Html字符串,其中一些有标题标签<b>Title</b>

facilities: "<b>Facilities</b><br/>24-hour security, Barbecue area, Car park, Clubhouse, Function room, Gym, Outdoor swimming pool, Playground, Swimming pool<br/><br/><b>Rooms</b><br/>Dining room, Ensuites, Living room, Maid\'s room, Utility room<br/><br/><b>Outdoor</b><br/>Balcony<br/><br/><b>View</b><br/>City, Open<br/><br/><b>Direction</b><br/>South East"

所以我使用NSRegularExpression模式从字符串中提取标题并存储在字符串数组中。然后,我将这些标题粗体(归因于字符串)和显示。所以这就是我这样做的方式:

var titlesArray = [String]()
let regex = try! NSRegularExpression(pattern: "<b>(.*?)</b>", options: [])
let basicDescription = facilities as NSString

regex.enumerateMatchesInString(facilities, options: [], range: NSMakeRange(0, facilities.characters.count)) { result, flags, stop in
  if let range = result?.rangeAtIndex(1) {
    titlesArray.append(basicDescription.substringWithRange(range))
  }
}

let convertedDescription = facilities.html2String as NSString
let attributedString = NSMutableAttributedString(string: convertedDescription as String, attributes: [NSFontAttributeName:UIFont.systemFontOfSize(14.0)])
let boldFontAttribute = [NSFontAttributeName: UIFont.boldSystemFontOfSize(15.0)]

if titlesArray.count > 0 {
   for i in 0..<titlesArray.count {
   attributedString.addAttributes(boldFontAttribute, range: convertedDescription.rangeOfString(titlesArray[i]))
   } 
}

所以,一切都很好。但问题是,有时我会收到带有重复单词的Html标记字符串,其中一个是带有标题标签的标题,另一个只是一个简单的单词,我不需要加粗。但是这个函数会查找那个单词并在for循环中加粗它,并忽略简单单词后面的真实标题。

这就是我得到的:

enter image description here

所以在这里,我怎么能忽略第一个“户外”和大胆的第二个我想要的。谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

在Objective-C中,不应该在Swift中翻译太难(因为看起来你已经知道了一些方法)。

使用attr1呈现

init(data:, options:, documentAttributes:)。我没有添加任何其他效果(例如粗体/普通,颜色的首选大小,你只需要枚举它并更改效果) 使用正则表达式,attr2更像是您想要的方式。它只是没有考虑所有标签,只是粗体,我几乎没有编写新行(<br/>\n)的替代品。但这可能是有用的东西。我没有对你的正则表达式做更多的测试(while循环可能会被卡住?)

NSString *str = @"<b>Facilities</b><br/>24-hour security, Barbecue area, Car park, Clubhouse, Function room, Gym, Outdoor swimming pool, Playground, Swimming pool<br/><br/><b>Rooms</b><br/>Dining room, Ensuites, Living room, Maid\'s room, Utility room<br/><br/><b>Outdoor</b><br/>Balcony<br/><br/><b>View</b><br/>City, Open<br/><br/><b>Direction</b><br/>South East";

NSError *errorAttr1 = nil;
NSAttributedString *attr1 = [[NSAttributedString alloc] initWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType} documentAttributes:nil error:&errorAttr1];
if (errorAttr1)
{
    NSLog(@"Error AttributedStr Conversion with initWithData:options:documentsAttributes:error: %@", errorAttr1);
}
else
{
    NSLog(@"attr1: %@", attr1);
    [_tv1 setAttributedText:attr1];

}

str = [str stringByReplacingOccurrencesOfString:@"<br/>" withString:@"\n"];

NSError *errorRegex = nil;
NSString *openingTag = @"<b>";
NSString *closingTag = @"</b>";
NSString *pattern = [NSString stringWithFormat:@"%@(.*?)%@", openingTag, closingTag];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&errorRegex];
if (errorRegex)
{
    NSLog(@"Error regex: %@", errorRegex);
    return;
}


NSDictionary *boldAttributes = @{NSForegroundColorAttributeName:[UIColor darkGrayColor],
                                 NSFontAttributeName:[UIFont boldSystemFontOfSize:15]};
NSDictionary *normalAttributes = @{NSForegroundColorAttributeName:[UIColor darkGrayColor],
                                   NSFontAttributeName:[UIFont systemFontOfSize:14]};

NSMutableAttributedString *attr2 = [[NSMutableAttributedString alloc] initWithString:str attributes:normalAttributes]; //Add the initial attributes there

//Now we'll add the specific attribues
NSTextCheckingResult *match = [regex firstMatchInString:[attr2 string] options:0 range:NSMakeRange(0, [attr2 length])];
while (match)
{
    NSRange range = [match range];
    NSString *foundStr = [[attr2 string] substringWithRange:range];
    NSAttributedString *temp = [[NSAttributedString alloc] initWithString:[foundStr substringWithRange:NSMakeRange([openingTag length], [foundStr length]-[openingTag length]-[closingTag length])] attributes:boldAttributes];
    [attr2 replaceCharactersInRange:range withAttributedString:temp];
    match = [regex firstMatchInString:[attr2 string] options:0 range:NSMakeRange(0, [attr2 length])];
}
NSLog(@"attr2: %@", attr2);
[_tv2 setAttributedText:attr2];

_tv1_tv2是两个UITextViewIBOulet)。 它呈现:( _tv1是顶部的,_tv2是第二个。)

enter image description here

答案 1 :(得分:0)

我不知道你究竟想做什么,但确实考虑使用initializer that takes HTML?

Playgrounds的示例代码是:

if let url = Bundle.main.url(forResource: "file", withExtension: "html") {
    do {
        let data = try Data(contentsOf: url)
        let attributedString = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
        let labelRect = CGRect(x: 0, y: 0, width: 500, height: 250)
        let label = UILabel(frame: labelRect)
        label.numberOfLines = 2
        label.attributedText = attributedString

    } catch {
        print(error.localizedDescription)
    }
}

使用此HTML:

<style>
    body {
     font-size: 20;
     font-family: sans-serif;
    }
</style>

<p><b>Hello</b> world</p>
<p>Good morning!</p>

输出如下:

enter image description here