美文网首页
正则表达式提取@#(@人,话题)

正则表达式提取@#(@人,话题)

作者: 苹果上的小豌豆 | 来源:发表于2018-07-31 16:21 被阅读0次

/// 点击的文本类型

enumTapRichTextType:Int{

    casenone =0    // 没有点击

    caseuser =1    // 点击了用户

    caselink =2    // 点击了链接

    casetopic =3    // 点击了话题

}

classRichLabel:UILabel{

    overridevarattributedText:NSAttributedString? {

        didSet{

            // 把文本设置为可变的

            letattributedString =NSMutableAttributedString(attributedString:attributedText!)

            // 添加属性

            attributedString.addAttribute(.font, value:font, range:NSRange(location:0, length: attributedString.length))

            // 设置 textStorage 的文本内容

            textStorage.setAttributedString(attributedString)

            // 匹配用户名 

            userRanges=ranges(from:"@.*?:")

            _=userRanges.map{textStorage.addAttribute(.foregroundColor, value:UIColor.blueFontColor(), range: $0) }

            // 匹配话题

            topicRanges=ranges(from:"#.*?#")

            _=topicRanges.map{textStorage.addAttribute(.foregroundColor, value:UIColor.blueFontColor(), range: $0) }

            // 匹配链接

            linkRanges=rangesOfLink()

            _=linkRanges.map{textStorage.addAttribute(.foregroundColor, value:UIColor.blueFontColor(), range: $0) }

        }

    }

    overridefuncdrawText(in rect:CGRect) {

        // 绘制字形,设置需要绘制的范围

        letrange =NSRange(location:0, length:textStorage.length)

        layoutManager.drawGlyphs(forGlyphRange: range, at: .zero)

    }

    overrideinit(frame:CGRect) {

        super.init(frame: frame)

        // 设置文本

        setupText()

    }

    requiredinit?(coder aDecoder:NSCoder) {

        super.init(coder: aDecoder)

        // 设置文本

        setupText()

    }

    /// 文本容器,文本可以排版的区域,默认是矩形,可以自定义区域大小

    privatelazyvartextContainer =NSTextContainer()

    /// 布局管理者,负责对文字进行编辑排版处理,将存储在 NSTextStorage 中的数据转换为可以在视图控件中显示的文本内容

    /// 并把字符编码映射到对应的字形上,然后将字形排版到 NSTextContainer 定义的区域中。

    privatelazyvarlayoutManager =NSLayoutManager()

    /// NSMutableAttributeString 的子类,主要用来存储文本的字符和相关属性

    /// 当 NSTextStorage 中的字符或属性发生改变时,会通知 NSLayoutManager,进而做到文本内容的显示更新。

    privatelazyvartextStorage =NSTextStorage()

    /// 记录用户名的范围

    privatelazyvaruserRanges = [NSRange]()

    /// 记录链接的范围

    privatelazyvarlinkRanges = [NSRange]()

    /// 记录话题的范围

    privatelazyvartopicRanges = [NSRange]()

    /// 定义一个闭包,点击回调

    typealiasTapRichText = (String,NSRange) -> ()

    varuserTapped:TapRichText?

    varlinkTapped:TapRichText?

    vartopicTapped:TapRichText?

    /// 点击的类型

    privatevartapRichTextType:TapRichTextType= .none

    /// 记录用户点击的 range

    varselectedRange =NSRange()

}

extension RichLabel {

    /// 设置文本

    privatefuncsetupText() {

        // 将 layoutManager 添加到 textStorage 中

        layoutManager.addTextContainer(textContainer)

        // 将 textContainer 添加到 layoutManager 中

        textStorage.addLayoutManager(layoutManager)

        // 设置可以与用户交互

        isUserInteractionEnabled = true

        // 间距设置 0

        textContainer.lineFragmentPadding = 0.0

    }

    overridefunclayoutSubviews() {

        super.layoutSubviews()

        // 设置容器的大小为 当前 label 的尺寸

        textContainer.size = frame.size

    }

    funcrangesOfLink() -> [NSRange] {

        // 检测正则表达式,NSDataDetector 是 NSRegularExpression 的子类

        let regex = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)

        returnresults(from: regex)

    }

    /// 返回正则表达式匹配的结果范围

    funcranges(from pattern:String) -> [NSRange] {

        // 创建正则表达式对象

        letregex =try!NSRegularExpression(pattern: pattern, options: [])

        returnresults(from: regex)

    }

    /// 返回正则表达式的结果

    privatefuncresults(from regex:NSRegularExpression) -> [NSRange] {

        // 开始匹配,返回结果

        letcheckingResults = regex.matches(in:textStorage.string, options: [], range:NSRange(location:0, length:textStorage.length))

        returncheckingResults.map({ $0.range})

    }

    /// 根据点击的坐标,获取范围

    privatefuncrange(of point:CGPoint) ->NSRange{

        // 判断 textStorage 长度是不是 0

        iftextStorage.length==0{returnNSRange() }

        // 在 textStorage 中的索引

        letindex =layoutManager.glyphIndex(for: point, in:textContainer)

        // 获取用户名的范围

        foruserRangeinuserRanges{

            ifindex > userRange.location&& index < userRange.location+ userRange.length{

                tapRichTextType= .user

                returnuserRange

            }

        }

        // 获取链接的范围

        forlinkRangeinlinkRanges{

            ifindex > linkRange.location&& index < linkRange.location+ linkRange.length{

                tapRichTextType= .link

                returnlinkRange

            }

        }

        // 获取话题的范围

        fortopicRangeintopicRanges{

            ifindex > topicRange.location&& index < topicRange.location+ topicRange.length{

                tapRichTextType= .topic

                returntopicRange

            }

        }

        returnNSRange()

    }

    /// 从 range 数组里返回一个 range

    /// 暂未使用

    funcrange(from ranges: [NSRange], index:Int) ->NSRange{

        // 获取话题的范围

        foriteminranges {

            ifindex > item.location&& index < item.location+ item.length{returnitem }

        }

        returnNSRange()

    }

}

extension RichLabel {

    overridefunctouchesBegan(_touches:Set, with event:UIEvent?) {

        // 获取点击的范围

        selectedRange=range(of: touches.first!.location(in:self))

        // 获取点击的范围的内容

        letcontent = (textStorage.stringasNSString).substring(with:selectedRange)

        // 判断点击的类型

        switch tapRichTextType {

        case.user:

            userTapped?(content,selectedRange)

        case.link:

            linkTapped?(content,selectedRange)

        case.topic:

            topicTapped?(content, selectedRange)

        default:

            break

        }

    }

}

相关文章

网友评论

      本文标题:正则表达式提取@#(@人,话题)

      本文链接:https://www.haomeiwen.com/subject/gayhvftx.html