MatchParser.m 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. //
  2. // MatchParser.m
  3. // CoreTextMagazine
  4. //
  5. // Created by weqia on 13-10-27.
  6. // Copyright (c) 2013年 Marin Todorov. All rights reserved.
  7. //
  8. #import "MatchParser.h"
  9. #import "NSStrUtil.h"
  10. static CGFloat ascentCallback( void *ref ){
  11. return 0;
  12. }
  13. static CGFloat descentCallback( void *ref ){
  14. return 0;
  15. }
  16. static CGFloat widthCallback( void* ref ){
  17. return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:@"width"] floatValue];
  18. // return 5;
  19. }
  20. static void deallocCallback(void * ref){
  21. }
  22. @implementation MatchParser
  23. @synthesize attrString,images,font,textColor,keyWorkColor,iconSize,ctFrame=_ctFrame,height=_height,width,line,paragraph,data,source=_source,miniWidth=_miniWidth,numberOfTotalLines=_numberOfTotalLines,heightOflimit=_heightOflimit,urlLink,phoneLink,mobieLink;
  24. -(id)init
  25. {
  26. self=[super init];
  27. if(self){
  28. _strs=[[NSMutableArray alloc]init];
  29. self.font=g_factory.font15;
  30. self.textColor=[UIColor blackColor];
  31. self.keyWorkColor=[UIColor grayColor];
  32. self.iconSize=19.0f;
  33. self.line=5.0f;
  34. self.paragraph=5.0f;
  35. self.MutiHeight=18.0f;
  36. self.fristlineindent=5.0f;
  37. self.mobieLink=YES;
  38. self.urlLink=YES;
  39. self.phoneLink=YES;
  40. _height=0;
  41. _heightOflimit=0;
  42. }
  43. return self;
  44. }
  45. +(NSDictionary*)getFaceMap
  46. {
  47. static NSDictionary * dic=nil;
  48. if(dic==nil){
  49. // NSString* path=[[NSBundle mainBundle] pathForResource:@"faceMap_ch" ofType:@"plist"];
  50. // dic =[NSDictionary dictionaryWithContentsOfFile:path];
  51. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  52. for (NSInteger i = 0; i < g_constant.emojiArray.count; i++) {
  53. NSDictionary * emoji = g_constant.emojiArray[i];
  54. NSString *EName = [emoji objectForKey:@"english"];
  55. NSString *totalEname = [NSString stringWithFormat:@"[%@]",EName];
  56. NSString *filename = [emoji objectForKey:@"filename"];
  57. [dict setValue:filename forKey:totalEname];
  58. }
  59. dic = [NSDictionary dictionaryWithDictionary:dict];
  60. }
  61. return dic;
  62. }
  63. +(NSString*)faceKeyForValue:(NSString*)value map:(NSDictionary*) map
  64. {
  65. NSArray * keys=[map allKeys];
  66. NSInteger count=[keys count];
  67. for(int i=0;i<count;i++)
  68. {
  69. NSString * key=[keys objectAtIndex:i];
  70. if([[map objectForKey:key] isEqualToString:value])
  71. return key;
  72. }
  73. return nil;
  74. }
  75. + (NSString *)emojiExist:(NSString *)key map:(NSDictionary *)map{
  76. NSArray * keys=[map allKeys];
  77. for (int i = 0; i < keys.count; i++) {
  78. if ([keys[i] isEqualToString:key]) {
  79. return map[keys[i]];
  80. }
  81. }
  82. return nil;
  83. }
  84. -(void)match:(NSString*)source
  85. {
  86. if([NSStrUtil isEmptyOrNull:source])
  87. return;
  88. _source=source;
  89. source=[NSStrUtil trimString:source];
  90. NSMutableString * text=[[NSMutableString alloc]init];
  91. NSMutableArray * imageArr=[[NSMutableArray alloc]init];
  92. NSRegularExpression * regular=[[NSRegularExpression alloc]initWithPattern:@"\\[[^\\[\\]\\s]+\\]" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  93. NSArray * array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])];
  94. NSInteger location=0;
  95. NSInteger count=[array count];
  96. for(int i=0;i<count;i++){
  97. NSTextCheckingResult * result=[array objectAtIndex:i];
  98. NSString * string=[source substringWithRange:result.range];
  99. // NSString * icon=[MatchParser faceKeyForValue:string map:[MatchParser getFaceMap]];
  100. NSString *icon = [MatchParser emojiExist:string map:[MatchParser getFaceMap]];
  101. [text appendString:[source substringWithRange:NSMakeRange(location, result.range.location-location)]];
  102. if(icon!=nil){
  103. NSMutableString * iconStr=[NSMutableString stringWithFormat:@"%@.png",icon];
  104. NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:iconStr,MatchParserImage,[NSNumber numberWithInteger:[text length]],MatchParserLocation,[NSNull null],MatchParserRects, nil];
  105. [imageArr addObject:dic];
  106. [text appendString:@" "];
  107. }else{
  108. [text appendString:string];
  109. }
  110. location=result.range.location+result.range.length;
  111. }
  112. [text appendString:[source substringWithRange:NSMakeRange(location, [source length]-location)]];
  113. CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL);
  114. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.textColor.CGColor,kCTForegroundColorAttributeName,nil];
  115. NSMutableAttributedString * attStr=[[NSMutableAttributedString alloc]initWithString:text attributes:attribute];
  116. for(NSDictionary * dic in imageArr){
  117. NSInteger location= [[dic objectForKey:MatchParserLocation] integerValue];
  118. CTRunDelegateCallbacks callbacks;
  119. callbacks.version = kCTRunDelegateVersion1;
  120. callbacks.getAscent = ascentCallback;
  121. callbacks.getWidth = widthCallback;
  122. callbacks.getDescent=descentCallback;
  123. NSDictionary* imgAttr = [NSDictionary dictionaryWithObjectsAndKeys: //2
  124. [NSNumber numberWithFloat:(self.iconSize+2)], @"width",
  125. nil] ;
  126. CTRunDelegateRef delegate=CTRunDelegateCreate(&callbacks, (__bridge void *)(imgAttr));
  127. NSDictionary* attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:
  128. //set the delegate
  129. (__bridge id)delegate, (NSString*)kCTRunDelegateAttributeName,
  130. nil];
  131. [attStr addAttributes:attrDictionaryDelegate range:NSMakeRange(location, 1)];
  132. }
  133. [self matchLink:text attrString:attStr offset:0 link:nil];
  134. CTParagraphStyleSetting lineBreakMode;
  135. CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
  136. lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
  137. lineBreakMode.value = &lineBreak;
  138. lineBreakMode.valueSize = sizeof(CTLineBreakMode);
  139. CGFloat lineSpace=self.line;//间距数据
  140. CTParagraphStyleSetting lineSpaceStyle;
  141. lineSpaceStyle.spec=kCTParagraphStyleSpecifierLineSpacingAdjustment;
  142. lineSpaceStyle.valueSize=sizeof(lineSpace);
  143. lineSpaceStyle.value=&lineSpace;
  144. //设置 段落间距
  145. CGFloat paragraphs = self.paragraph;
  146. CTParagraphStyleSetting paragraphStyle;
  147. paragraphStyle.spec = kCTParagraphStyleSpecifierParagraphSpacing;
  148. paragraphStyle.valueSize = sizeof(CGFloat);
  149. paragraphStyle.value = &paragraphs;
  150. //创建样式数组
  151. CTParagraphStyleSetting settings[] = {
  152. lineBreakMode,lineSpaceStyle,paragraphStyle
  153. };
  154. //设置样式
  155. CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 3);
  156. // build attributes
  157. NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(__bridge id)style forKey:(id)kCTParagraphStyleAttributeName ];
  158. [attStr addAttributes:attributes range:NSMakeRange(0, [text length])];
  159. CFRelease(fontRef);
  160. CFRelease(style);
  161. self.attrString=attStr;
  162. self.images=imageArr;
  163. }
  164. -(void)match:(NSString*)source atCallBack:(BOOL(^)(NSString*))atString
  165. {
  166. [self match:source atCallBack:atString title:nil];
  167. }
  168. -(void)match:(NSString *)source atCallBack:(BOOL (^)(NSString *))atString title:(NSAttributedString*)title1
  169. {
  170. [self match:source atCallBack:atString title:title1 link:nil];
  171. }
  172. -(void)match:(NSString *)source atCallBack:(BOOL (^)(NSString *))atString title:(NSAttributedString *)title1 link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link
  173. {
  174. if([NSStrUtil isEmptyOrNull:source])
  175. return;
  176. _source=source;
  177. source=[NSStrUtil trimString:source];
  178. NSMutableString * text=[[NSMutableString alloc]init];
  179. NSMutableArray * imageArr=[[NSMutableArray alloc]init];
  180. NSRegularExpression * regular=[[NSRegularExpression alloc]initWithPattern:@"\\[[^\\[\\]\\s]+\\]" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  181. NSArray * array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])];
  182. NSUInteger offset=0;
  183. if(title1){
  184. offset=[title1 length];
  185. }
  186. NSInteger location=0;
  187. NSUInteger count=[array count];
  188. for(int i=0;i<count;i++){
  189. NSTextCheckingResult * result=[array objectAtIndex:i];
  190. NSString * string=[source substringWithRange:result.range];
  191. // NSString * icon=[MatchParser faceKeyForValue:string map:[MatchParser getFaceMap]];
  192. NSString *icon = [MatchParser emojiExist:string map:[MatchParser getFaceMap]];
  193. [text appendString:[source substringWithRange:NSMakeRange(location, result.range.location-location)]];
  194. if(icon!=nil){
  195. NSMutableString * iconStr=[NSMutableString stringWithFormat:@"%@.png",icon];
  196. NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:iconStr,MatchParserImage,[NSNumber numberWithInteger:[text length]+offset],MatchParserLocation,[NSNull null],MatchParserRects,[NSNull null],MatchParserLine, nil];
  197. [imageArr addObject:dic];
  198. [text appendString:@" "];
  199. }else{
  200. [text appendString:string];
  201. }
  202. location=result.range.location+result.range.length;
  203. }
  204. [text appendString:[source substringWithRange:NSMakeRange(location, [source length]-location)]];
  205. CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL);
  206. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.textColor.CGColor,kCTForegroundColorAttributeName,nil];
  207. NSMutableAttributedString * attStr=[[NSMutableAttributedString alloc]init];
  208. if(title1!=nil&&[title1 isKindOfClass:[NSAttributedString class]])
  209. [attStr appendAttributedString:title1];
  210. [attStr appendAttributedString:[[NSAttributedString alloc] initWithString:text attributes:attribute]];
  211. for(NSDictionary * dic in imageArr){
  212. CTRunDelegateCallbacks callbacks;
  213. callbacks.version = kCTRunDelegateVersion1;
  214. callbacks.getAscent = ascentCallback;
  215. callbacks.getWidth = widthCallback;
  216. callbacks.getDescent=descentCallback;
  217. callbacks.dealloc=deallocCallback;
  218. NSDictionary* imgAttr = [NSDictionary dictionaryWithObjectsAndKeys: //2
  219. [NSNumber numberWithFloat:(self.iconSize+2)], @"width",
  220. nil] ;
  221. CTRunDelegateRef delegate=CTRunDelegateCreate(&callbacks, (__bridge void *)(imgAttr));
  222. NSDictionary*attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:
  223. //set the delegate
  224. (__bridge id)delegate, (NSString*)kCTRunDelegateAttributeName,
  225. nil];
  226. NSInteger location= [[dic objectForKey:MatchParserLocation] integerValue];
  227. [attStr addAttributes:attrDictionaryDelegate range:NSMakeRange(location, 1)];
  228. }
  229. regular=[[NSRegularExpression alloc]initWithPattern:@"@[^@\\s]+" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  230. array=[regular matchesInString:text options:0 range:NSMakeRange(0, [text length])];
  231. for( NSTextCheckingResult * result in array){
  232. NSString * string =[text substringWithRange:result.range];
  233. if([string hasPrefix:@"@"]){
  234. string=[string substringFromIndex:1];
  235. if(atString){
  236. if(atString(string)){
  237. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil];
  238. [attStr addAttributes:attribute range:NSMakeRange(result.range.location+offset, result.range.length)];
  239. }else{
  240. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.textColor.CGColor,kCTForegroundColorAttributeName,nil];
  241. [attStr addAttributes:attribute range:NSMakeRange(result.range.location+offset, result.range.length)];
  242. }
  243. }else{
  244. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.textColor.CGColor,kCTForegroundColorAttributeName,nil];
  245. [attStr addAttributes:attribute range:NSMakeRange(result.range.location+offset, result.range.length)];
  246. }
  247. }
  248. }
  249. [self matchLink:text attrString:attStr offset:(int)offset link:link];
  250. CTParagraphStyleSetting lineBreakMode;
  251. CTLineBreakMode lineBreak = kCTLineBreakByCharWrapping;
  252. lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
  253. lineBreakMode.value = &lineBreak;
  254. lineBreakMode.valueSize = sizeof(CTLineBreakMode);
  255. CGFloat lineSpace=self.line;//间距数据
  256. CTParagraphStyleSetting lineSpaceStyle;
  257. lineSpaceStyle.spec=kCTParagraphStyleSpecifierLineSpacingAdjustment;
  258. lineSpaceStyle.valueSize=sizeof(lineSpace);
  259. lineSpaceStyle.value=&lineSpace;
  260. //设置 段落间距
  261. CGFloat paragraphs = self.paragraph;
  262. CTParagraphStyleSetting paragraphStyle;
  263. paragraphStyle.spec = kCTParagraphStyleSpecifierParagraphSpacing;
  264. paragraphStyle.valueSize = sizeof(CGFloat);
  265. paragraphStyle.value = &paragraphs;
  266. //多行行高
  267. CGFloat MutiHeight =self.MutiHeight;
  268. CTParagraphStyleSetting Muti;
  269. Muti.spec = kCTParagraphStyleSpecifierLineHeightMultiple;
  270. Muti.value = &MutiHeight;
  271. Muti.valueSize = sizeof(float);
  272. //首行缩进
  273. CGFloat fristlineindent =self.fristlineindent;
  274. CTParagraphStyleSetting fristline;
  275. fristline.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent;
  276. fristline.value = &fristlineindent;
  277. fristline.valueSize = sizeof(float);
  278. //创建样式数组
  279. CTParagraphStyleSetting settings[] = {
  280. lineBreakMode,lineSpaceStyle,paragraphStyle,Muti,fristline
  281. };
  282. //设置样式
  283. CTParagraphStyleRef style = CTParagraphStyleCreate(settings, 3);
  284. // build attributes
  285. NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(__bridge id)style forKey:(id)kCTParagraphStyleAttributeName ];
  286. [attStr addAttributes:attributes range:NSMakeRange(0, [text length]+offset)];
  287. CFRelease(fontRef);
  288. CFRelease(style);
  289. self.attrString=attStr;
  290. self.images=imageArr;
  291. [self buildFrames];
  292. }
  293. #pragma -mark 私有方法
  294. -(void)buildFrames
  295. {
  296. CGMutablePathRef path = CGPathCreateMutable(); //2
  297. CGRect textFrame = CGRectMake(0,0, width, 10000);
  298. CGPathAddRect(path, NULL, textFrame );
  299. CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.attrString);
  300. CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [self.attrString length]), path, NULL);
  301. NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); //1
  302. CGPoint origins[[lines count]];
  303. CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); //2
  304. #pragma -mark 获得内容的总高度
  305. //获得内容的总高度
  306. if([lines count]>=1){
  307. float line_y = (float) origins[[lines count] -1].y; //最后一行line的原点y坐标
  308. CGFloat ascent;
  309. CGFloat descent;
  310. CGFloat leading;
  311. CTLineRef line1 = (__bridge CTLineRef) [lines lastObject];
  312. CTLineGetTypographicBounds(line1, &ascent, &descent, &leading);
  313. float total_height =10000- line_y + descent+1 ; //+1为了纠正descent转换成int小数点后舍去的值
  314. _height=total_height+2;
  315. }else{
  316. _height=0;
  317. }
  318. lines = (__bridge NSArray *)CTFrameGetLines(frame); //1
  319. CGPoint Origins[[lines count]];
  320. CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), Origins); //2
  321. #pragma -mark 获取内容行数 以及 一行时内容的宽度
  322. // 获取内容行数 以及 一行时,内容的宽度
  323. _numberOfTotalLines=(int)[lines count];
  324. if(_numberOfTotalLines>1){
  325. _miniWidth=self.width;
  326. }else{
  327. CTLineRef lineOne=(__bridge CTLineRef)lines[0];
  328. _miniWidth=CTLineGetTypographicBounds(lineOne, nil, nil, nil);
  329. }
  330. #pragma -mark 获取限定行数后内容的高度
  331. // 获取限定行数后内容的高度
  332. if(_numberOfTotalLines<=_numberOfLimitLines||_numberOfLimitLines==0){
  333. _heightOflimit=_height;
  334. }else{
  335. CTLineRef line1=(__bridge CTLineRef)(lines[_numberOfLimitLines-1]);
  336. float line_y = (float) origins[_numberOfLimitLines -1].y; //最后一行line的原点y坐标
  337. CGFloat ascent;
  338. CGFloat descent;
  339. CGFloat leading;
  340. CTLineGetTypographicBounds(line1, &ascent, &descent, &leading);
  341. float total_height =10000- line_y + descent+1 ; //+1为了纠正descent转换成int小数点后舍去的值
  342. _heightOflimit=total_height+2;
  343. }
  344. #pragma -mark 解析表情图片
  345. // 解析表情图片
  346. if([self.images count]>0){
  347. int imgIndex = 0; //3
  348. NSDictionary* nextImage = [self.images objectAtIndex:imgIndex];
  349. // NSRange imgLocation =[[nextImage objectForKey:MatchParserLocation] rangeValue];
  350. NSRange imgLocation = NSMakeRange([[nextImage objectForKey:MatchParserLocation] intValue], 1);
  351. int lineIndex = 0;
  352. // for (NSInteger i = 0; i < lines.count; i ++) {
  353. for (id lineObj in lines) { //5
  354. CTLineRef line1 = (__bridge CTLineRef)lineObj;
  355. // CTLineRef line1 = (__bridge CTLineRef)lines[i];
  356. // NSArray *runs = (__bridge NSArray *)CTLineGetGlyphRuns(line1);
  357. // for (NSInteger j = 0; j < runs.count; j ++) {
  358. for (id runObj in (__bridge NSArray *)CTLineGetGlyphRuns(line1)) { //6
  359. CTRunRef run = (__bridge CTRunRef)runObj;
  360. // CTRunRef run = (__bridge CTRunRef)runs[j];
  361. CFRange runRange = CTRunGetStringRange(run);
  362. if ( runRange.location==imgLocation.location) { //7
  363. CGRect runBounds;
  364. runBounds.size.width =iconSize; //8
  365. runBounds.size.height =iconSize;
  366. CFRange range = CFRangeMake(0, 0);
  367. CGPoint point;
  368. CTRunGetPositions(run, range, &point);
  369. runBounds.origin.x = point.x+ Origins[lineIndex].x+1;
  370. runBounds.origin.y = point.y-4+Origins[lineIndex].y;
  371. // NSLog(@"poing x: %f, y:%f",point.x,point.y);
  372. NSMutableDictionary * dic=[self.images objectAtIndex:imgIndex];
  373. [dic setObject:[NSValue valueWithCGRect:runBounds] forKey:MatchParserRects];
  374. [dic setObject:[NSNumber numberWithInt:lineIndex] forKey:MatchParserLine];
  375. //load the next image //12
  376. imgIndex++;
  377. if (imgIndex < [self.images count]) {
  378. nextImage = [self.images objectAtIndex: imgIndex];
  379. imgLocation = NSMakeRange([[nextImage objectForKey:MatchParserLocation] intValue], 1);
  380. }else{
  381. lineIndex = (int)[lines count];
  382. break;
  383. }
  384. }
  385. }
  386. if(lineIndex >= [lines count])
  387. break;
  388. lineIndex++;
  389. }
  390. }
  391. #pragma -mark 解析网址链接
  392. // 解析网址链接
  393. if([self.links count]>0){
  394. int linkIndex = 0; //3
  395. NSDictionary* nextLink = [self.links objectAtIndex:linkIndex];
  396. NSRange linkRange =[[nextLink objectForKey:MatchParserRange] rangeValue];
  397. int lineIndex = 0;
  398. for (id lineObj in lines) { //5
  399. CTLineRef line1 = (__bridge CTLineRef)lineObj;
  400. for (id runObj in (__bridge NSArray *)CTLineGetGlyphRuns(line1)) { //6
  401. CTRunRef run = (__bridge CTRunRef)runObj;
  402. CFRange runRange = CTRunGetStringRange(run);
  403. if ( runRange.location>=linkRange.location&&runRange.location<(linkRange.location+linkRange.length)) { //7
  404. CGRect runBounds;
  405. CGFloat ascent;
  406. CGFloat descent;
  407. runBounds.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, NULL); //8
  408. runBounds.size.height = ascent + descent;
  409. CGFloat xOffset = CTLineGetOffsetForStringIndex(line1, CTRunGetStringRange(run).location, NULL); //9
  410. runBounds.origin.x = Origins[lineIndex].x + xOffset ;
  411. runBounds.origin.y = Origins[lineIndex].y ;
  412. runBounds.origin.y=10000-runBounds.origin.y-runBounds.size.height;
  413. // NSLog(@"poing x: %f, y:%f",point.x,point.y);
  414. NSMutableDictionary * dic=[self.links objectAtIndex:linkIndex];
  415. NSMutableArray * rects=[dic objectForKey:MatchParserRects];
  416. [rects addObject:[NSValue valueWithCGRect:runBounds]];
  417. //load the next image //12
  418. if((runRange.location+runRange.length)>=(linkRange.location+linkRange.length)){
  419. linkIndex++;
  420. if (linkIndex < [self.links count]) {
  421. nextLink = [self.links objectAtIndex: linkIndex];
  422. linkRange = [[nextLink objectForKey: MatchParserRange] rangeValue];
  423. }else{
  424. _ctFrame=(__bridge id)frame;
  425. CFRelease(frame);
  426. CFRelease(path);
  427. CFRelease(framesetter);
  428. return;
  429. }
  430. }
  431. }
  432. }
  433. lineIndex++;
  434. }
  435. }
  436. _ctFrame=(__bridge id)frame;
  437. CFRelease(frame);
  438. CFRelease(path);
  439. CFRelease(framesetter);
  440. }
  441. -(void)matchLink:(NSString*)text attrString:(NSMutableAttributedString*)attStr offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link
  442. {
  443. _links=[[NSMutableArray alloc]init];
  444. if(self.urlLink){
  445. [self matchUrlLink:text attrString:attStr offset:offset link:link];
  446. }
  447. // if(self.phoneLink){
  448. // [self matchPhoneLink:text attrString:attStr offset:offset link:link];
  449. // }
  450. if(self.mobieLink){
  451. [self matchMobieLink:text attrString:attStr offset:offset link:link];
  452. }
  453. [_links sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
  454. NSDictionary * dic1=obj1;
  455. NSDictionary * dic2=obj2;
  456. NSRange range1=((NSValue *)[dic1 objectForKey:MatchParserRange]).rangeValue;
  457. NSRange range2=((NSValue *)[dic2 objectForKey:MatchParserRange]).rangeValue;
  458. if (range1.location<range2.location) {
  459. return NSOrderedAscending;
  460. }else{
  461. return NSOrderedDescending;
  462. }
  463. }];
  464. }
  465. //匹配网址
  466. -(void)matchUrlLink:(NSString*)source attrString:(NSMutableAttributedString*)attrString1 offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link
  467. {
  468. // NSRegularExpression*regular=[[NSRegularExpression alloc]initWithPattern:@"(http|ftp|https):\\/\\/[\\w\\-_]+(\\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  469. NSRegularExpression*regular=[[NSRegularExpression alloc]initWithPattern:@"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  470. NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])];
  471. for( NSTextCheckingResult * result in array){
  472. if(link==nil){
  473. CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL);
  474. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil];
  475. [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)];
  476. CFRelease(fontRef);
  477. }else{
  478. link(attrString1,NSMakeRange(result.range.location+offset,result.range.length));
  479. }
  480. NSString * string=[source substringWithRange:result.range];
  481. NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypeUrl,MatchParserLinkType,nil];
  482. [_links addObject:dic];
  483. }
  484. }
  485. //匹配手机号
  486. -(void)matchMobieLink:(NSString*)source attrString:(NSMutableAttributedString*)attrString1 offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link
  487. {
  488. NSRegularExpression*regular=[[NSRegularExpression alloc]initWithPattern:@"(\\(86\\))?(13[0-9]|15[0-35-9]|18[0125-9])\\d{8}" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  489. NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])];
  490. for( NSTextCheckingResult * result in array){
  491. if(link==nil){
  492. CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL);
  493. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil];
  494. [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)];
  495. CFRelease(fontRef);
  496. }else{
  497. link(attrString1,NSMakeRange(result.range.location+offset,result.range.length));
  498. }
  499. NSString * string=[source substringWithRange:result.range];
  500. NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypeMobie,MatchParserLinkType,nil];
  501. [_links addObject:dic];
  502. }
  503. }
  504. //匹配座机号
  505. -(void)matchPhoneLink:(NSString*)source attrString:(NSMutableAttributedString*)attrString1 offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link
  506. {
  507. NSRegularExpression*regular=[[NSRegularExpression alloc]initWithPattern:@"(\\d{11,12})|(\\d{7,8})|((\\d{4}|\\d{3})-(\\d{7,8}))|((\\d{4}|\\d{3})-(\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d{1}))|((\\d{7,8})-(\\d{4}|\\d{3}|\\d{2}|\\d{1}))$" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  508. NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])];
  509. for( NSTextCheckingResult * result in array){
  510. NSRegularExpression*regular1=[[NSRegularExpression alloc]initWithPattern:@"^(\\(86\\))?(13[0-9]|15[7-9]|152|153|156|18[7-9])\\d{8}" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil];
  511. NSString * string=[source substringWithRange:result.range];
  512. NSUInteger numberOfMatches = [regular1 numberOfMatchesInString:string
  513. options:0
  514. range:NSMakeRange(0, [string length])];
  515. if (numberOfMatches>0) {
  516. return;
  517. }
  518. if(link==nil){
  519. CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL);
  520. NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil];
  521. [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)];
  522. CFRelease(fontRef);
  523. }else{
  524. link(attrString1,NSMakeRange(result.range.location+offset,result.range.length));
  525. }
  526. NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypePhone,MatchParserLinkType,nil];
  527. [_links addObject:dic];
  528. }
  529. }
  530. @end