2015-05-22 20 views
6

tôi có chức năng sau đây để tìm và làm nổi bật hashtags hoặc đề cập (@ hay #) trong một UILabel:Làm cách nào để tô sáng văn bản trong chuỗi chứa biểu tượng cảm xúc trong Swift?

class func addLinkAttribute(pattern: String, 
     toText text: String, 
     withAttributeName attributeName : String, 
     toAttributedString attributedString :NSMutableAttributedString, 
     withLinkAttributes linkAttributes: [NSObject : AnyObject]) { 
     var error: NSError? 
     if let regex = NSRegularExpression(pattern: pattern, options:.CaseInsensitive, error: &error) { 
      regex.enumerateMatchesInString(text, options: .allZeros, range: NSMakeRange(0, count(text))) { result, flags, stop in 
       let range = result.range 
       let start = advance(text.startIndex, range.location) 
       let end = advance(start, range.length) 
       let foundText = text.substringWithRange(Range<String.Index>(start: start,end: end)) 
       var linkAttributesWithName = linkAttributes 
       linkAttributesWithName[attributeName] = foundText 
       attributedString.addAttributes(linkAttributesWithName, range: range) 
      } 
     } 
    } 

Nếu tôi vượt qua một hashtag (#)(\\w+) hoặc đề cập đến (@)(\\w+) mẫu mã hoạt động hoàn hảo nhưng nếu văn bản có chứa một Emoji phạm vi được bù đắp bởi số lượng các biểu tượng cảm xúc trước nó:

enter image description here

tôi biết xử lý chuỗi Swift cách khác nhau để Objective-C, vì count(string)count(string.utf16) cho tôi kết quả khác nhau, nhưng tôi stumped như thế nào để giải thích cho điều này khi sử dụng một biểu thức chính quy.

Tôi chỉ có thể kiểm tra sự khác biệt giữa 2 lần đếm và bù lại phạm vi, nhưng điều này có vẻ sai và gây hại cho tôi. Phải có một cách khác.

Trả lời

8

Tương tự như trong Swift extract regex matches, một giải pháp khả thi là để chuyển đổi Swift cho String một NSString và áp dụng các NSRange s trả về bởi enumerateMatchesInString()-NSString rằng:

class func addLinkAttribute(pattern: String, 
    toText text: String, 
    withAttributeName attributeName : String, 
    toAttributedString attributedString :NSMutableAttributedString, 
    withLinkAttributes linkAttributes: [NSObject : AnyObject]) { 
    let nsText = text as NSString 
    var error: NSError? 
    if let regex = NSRegularExpression(pattern: pattern, options:.CaseInsensitive, error: &error) { 
     regex.enumerateMatchesInString(text, options: .allZeros, range: NSMakeRange(0, nsText.length)) { 
      result, _, _ in 
      let range = result.range 
      let foundText = nsText.substringWithRange(range) 
      var linkAttributesWithName = linkAttributes 
      linkAttributesWithName[attributeName] = foundText 
      attributedString.addAttributes(linkAttributesWithName, range: range) 
     } 
    } 
} 

(Giải pháp thay thế .) Có thể chuyển đổi một số NSRange thành Range<String.Index> mà không chuyển đổi trung gian thành NSString. Với

extension String { 
    func rangeFromNSRange(nsRange : NSRange) -> Range<String.Index>? { 
     let utf16start = self.utf16.startIndex 
     if let from = String.Index(self.utf16.startIndex + nsRange.location, within: self), 
      let to = String.Index(self.utf16.startIndex + nsRange.location + nsRange.length, within: self) { 
       return from ..< to 
     } 
     return nil 
    } 
} 

từ https://stackoverflow.com/a/30404532/1187415, mã của bạn có thể được viết như

class func addLinkAttribute(pattern: String, 
    toText text: String, 
    withAttributeName attributeName : String, 
    toAttributedString attributedString :NSMutableAttributedString, 
    withLinkAttributes linkAttributes: [NSObject : AnyObject]) { 

    var error: NSError? 
    if let regex = NSRegularExpression(pattern: pattern, options:.CaseInsensitive, error: &error) { 
     regex.enumerateMatchesInString(text, options: .allZeros, range: NSMakeRange(0, count(text.utf16))) { 
      result, _, _ in 
      let nsRange = result.range 
      if let strRange = text.rangeFromNSRange(nsRange) { 
       let foundText = text.substringWithRange(strRange) 
       var linkAttributesWithName = linkAttributes 
       linkAttributesWithName[attributeName] = foundText 
       attributedString.addAttributes(linkAttributesWithName, range: nsRange) 
      } 
     } 
    } 
} 

và đó cũng nên làm việc một cách chính xác cho tất cả các loại mở rộng grapheme cụm (biểu tượng cảm xúc, chỉ số khu vực vv ...)

+0

Hoạt động hoàn hảo! Cảm ơn bạn. Tôi chắc chắn có một cách để làm điều này mà không dựa vào 'NSString' nhưng điều này hoạt động và tôi không nghĩ rằng' NSString' sẽ sớm diễn ra. –

+1

@MichaelGaylord: Bạn đã khơi dậy tham vọng của tôi, xem câu trả lời cập nhật :) –

+0

@MartinR thật tuyệt vời! Cám ơn vì đã chia sẻ! làm việc như một say mê! – Andres

Các vấn đề liên quan