你还在为不会写正则而抓狂?
你还在为如何识别字符串中的
电话号码
、链接
、日期
、地址
...并实现国际化而烦恼?那么你会在看完本文章之后不会抓狂,不会烦恼,依旧觉得生活很美好!
进入正题!!!
其实 Apple 已经帮我们定义好了这么一个
class
, NSDataDetector
只是知道这个类的人甚少。 NSDataDetector
它是继承至NSRegularExpression
的,也就是我们所说的正则表达式。NSDataDetector
的使用很简单,有一个类方法和一个实例方法。
+ (nullable NSDataDetector *)dataDetectorWithTypes:(NSTextCheckingTypes)checkingTypes error:(NSError **)error;
- (nullable instancetype)initWithTypes:(NSTextCheckingTypes)checkingTypes error:(NSError **)error NS_DESIGNATED_INITIALIZER;
这里的type
就是我们需要匹配的类型。这些 type 都是系统帮我们定义好的,当然我们也可以自己自定义type
。
typedef NS_OPTIONS(uint64_t, NSTextCheckingType) { // a single type
NSTextCheckingTypeOrthography = 1ULL << 0, // language identification
NSTextCheckingTypeSpelling = 1ULL << 1, // spell checking
NSTextCheckingTypeGrammar = 1ULL << 2, // grammar checking
NSTextCheckingTypeDate = 1ULL << 3, // date/time detection
NSTextCheckingTypeAddress = 1ULL << 4, // address detection
NSTextCheckingTypeLink = 1ULL << 5, // link detection
NSTextCheckingTypeQuote = 1ULL << 6, // smart quotes
NSTextCheckingTypeDash = 1ULL << 7, // smart dashes
NSTextCheckingTypeReplacement = 1ULL << 8, // fixed replacements, such as copyright symbol for (c)
NSTextCheckingTypeCorrection = 1ULL << 9, // autocorrection
NSTextCheckingTypeRegularExpression NS_ENUM_AVAILABLE(10_7, 4_0) = 1ULL << 10, // regular expression matches
NSTextCheckingTypePhoneNumber NS_ENUM_AVAILABLE(10_7, 4_0) = 1ULL << 11, // phone number detection
NSTextCheckingTypeTransitInformation NS_ENUM_AVAILABLE(10_7, 4_0) = 1ULL << 12 // transit (e.g. flight) info detection
};
这仅仅是第一步,这一步就好比我们写好了正则表达式,那么下一步就是将它运用在字符串中进行匹配。这里有5种方法可共选择
//1.检测然后对每个检测到的数据进行操作
- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block;
//2.检测获得检测得到的数组
- (NSArray *)matchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
//3.获得检测得到的总数
- (NSUInteger)numberOfMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
//4.第一个检测到的数据
- (NSTextCheckingResult *)firstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
//5.第一检测到的数据的Range
- (NSRange)rangeOfFirstMatchInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range;
匹配到了对应的字符串并知道了字符串对应所在的NSRange
,接下来就可以利用NSMutableAttributedString
来让这些字符串高亮。
高亮文本的事件响应
UITextView
- 在
UITextView
中可以直接响应高亮文本的事件,先设置 UITextView 的delegate
,并实现- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
协议。此时要设置 UITextView 的editable
为NO
,不然不会走回调的API
。 - 做完这些之后还需要设置文本响应的 range,根据上面获取到的文本和 range,我们可以根据属性字符串的
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
方法设置响应事件,name
为NSLinkAttributeName
,value
为响应事件接收到的 value,range
为需要响应事件的 range。
UILabel
其实在 Label 中实现文本高亮并实现事件的响应,在 Github 上面有很多库了,例如YYText中的 YYLabel、TTTAttributedLabel等等,太多了就不一一列举了,但是在YYLabel
中同时实现长按事件和点击事件的时候,响应长按事件之后还会响应点击事件,这时候就需要我们自己手动处理一下了。
参考文章:初识 NSDataDetector