// // MatchParser.m // CoreTextMagazine // // Created by weqia on 13-10-27. // Copyright (c) 2013年 Marin Todorov. All rights reserved. // #import "MatchParser.h" #import "NSStrUtil.h" static CGFloat ascentCallback( void *ref ){ return 0; } static CGFloat descentCallback( void *ref ){ return 0; } static CGFloat widthCallback( void* ref ){ return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:@"width"] floatValue]; // return 5; } static void deallocCallback(void * ref){ } @implementation MatchParser @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; -(id)init { self=[super init]; if(self){ _strs=[[NSMutableArray alloc]init]; self.font=g_factory.font15; self.textColor=[UIColor blackColor]; self.keyWorkColor=[UIColor grayColor]; self.iconSize=19.0f; self.line=5.0f; self.paragraph=5.0f; self.MutiHeight=18.0f; self.fristlineindent=5.0f; self.mobieLink=YES; self.urlLink=YES; self.phoneLink=YES; _height=0; _heightOflimit=0; } return self; } +(NSDictionary*)getFaceMap { static NSDictionary * dic=nil; if(dic==nil){ // NSString* path=[[NSBundle mainBundle] pathForResource:@"faceMap_ch" ofType:@"plist"]; // dic =[NSDictionary dictionaryWithContentsOfFile:path]; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; for (NSInteger i = 0; i < g_constant.emojiArray.count; i++) { NSDictionary * emoji = g_constant.emojiArray[i]; NSString *EName = [emoji objectForKey:@"english"]; NSString *totalEname = [NSString stringWithFormat:@"[%@]",EName]; NSString *filename = [emoji objectForKey:@"filename"]; [dict setValue:filename forKey:totalEname]; } dic = [NSDictionary dictionaryWithDictionary:dict]; } return dic; } +(NSString*)faceKeyForValue:(NSString*)value map:(NSDictionary*) map { NSArray * keys=[map allKeys]; NSInteger count=[keys count]; for(int i=0;i=1){ float line_y = (float) origins[[lines count] -1].y; //最后一行line的原点y坐标 CGFloat ascent; CGFloat descent; CGFloat leading; CTLineRef line1 = (__bridge CTLineRef) [lines lastObject]; CTLineGetTypographicBounds(line1, &ascent, &descent, &leading); float total_height =10000- line_y + descent+1 ; //+1为了纠正descent转换成int小数点后舍去的值 _height=total_height+2; }else{ _height=0; } lines = (__bridge NSArray *)CTFrameGetLines(frame); //1 CGPoint Origins[[lines count]]; CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), Origins); //2 #pragma -mark 获取内容行数 以及 一行时内容的宽度 // 获取内容行数 以及 一行时,内容的宽度 _numberOfTotalLines=(int)[lines count]; if(_numberOfTotalLines>1){ _miniWidth=self.width; }else{ CTLineRef lineOne=(__bridge CTLineRef)lines[0]; _miniWidth=CTLineGetTypographicBounds(lineOne, nil, nil, nil); } #pragma -mark 获取限定行数后内容的高度 // 获取限定行数后内容的高度 if(_numberOfTotalLines<=_numberOfLimitLines||_numberOfLimitLines==0){ _heightOflimit=_height; }else{ CTLineRef line1=(__bridge CTLineRef)(lines[_numberOfLimitLines-1]); float line_y = (float) origins[_numberOfLimitLines -1].y; //最后一行line的原点y坐标 CGFloat ascent; CGFloat descent; CGFloat leading; CTLineGetTypographicBounds(line1, &ascent, &descent, &leading); float total_height =10000- line_y + descent+1 ; //+1为了纠正descent转换成int小数点后舍去的值 _heightOflimit=total_height+2; } #pragma -mark 解析表情图片 // 解析表情图片 if([self.images count]>0){ int imgIndex = 0; //3 NSDictionary* nextImage = [self.images objectAtIndex:imgIndex]; // NSRange imgLocation =[[nextImage objectForKey:MatchParserLocation] rangeValue]; NSRange imgLocation = NSMakeRange([[nextImage objectForKey:MatchParserLocation] intValue], 1); int lineIndex = 0; // for (NSInteger i = 0; i < lines.count; i ++) { for (id lineObj in lines) { //5 CTLineRef line1 = (__bridge CTLineRef)lineObj; // CTLineRef line1 = (__bridge CTLineRef)lines[i]; // NSArray *runs = (__bridge NSArray *)CTLineGetGlyphRuns(line1); // for (NSInteger j = 0; j < runs.count; j ++) { for (id runObj in (__bridge NSArray *)CTLineGetGlyphRuns(line1)) { //6 CTRunRef run = (__bridge CTRunRef)runObj; // CTRunRef run = (__bridge CTRunRef)runs[j]; CFRange runRange = CTRunGetStringRange(run); if ( runRange.location==imgLocation.location) { //7 CGRect runBounds; runBounds.size.width =iconSize; //8 runBounds.size.height =iconSize; CFRange range = CFRangeMake(0, 0); CGPoint point; CTRunGetPositions(run, range, &point); runBounds.origin.x = point.x+ Origins[lineIndex].x+1; runBounds.origin.y = point.y-4+Origins[lineIndex].y; // NSLog(@"poing x: %f, y:%f",point.x,point.y); NSMutableDictionary * dic=[self.images objectAtIndex:imgIndex]; [dic setObject:[NSValue valueWithCGRect:runBounds] forKey:MatchParserRects]; [dic setObject:[NSNumber numberWithInt:lineIndex] forKey:MatchParserLine]; //load the next image //12 imgIndex++; if (imgIndex < [self.images count]) { nextImage = [self.images objectAtIndex: imgIndex]; imgLocation = NSMakeRange([[nextImage objectForKey:MatchParserLocation] intValue], 1); }else{ lineIndex = (int)[lines count]; break; } } } if(lineIndex >= [lines count]) break; lineIndex++; } } #pragma -mark 解析网址链接 // 解析网址链接 if([self.links count]>0){ int linkIndex = 0; //3 NSDictionary* nextLink = [self.links objectAtIndex:linkIndex]; NSRange linkRange =[[nextLink objectForKey:MatchParserRange] rangeValue]; int lineIndex = 0; for (id lineObj in lines) { //5 CTLineRef line1 = (__bridge CTLineRef)lineObj; for (id runObj in (__bridge NSArray *)CTLineGetGlyphRuns(line1)) { //6 CTRunRef run = (__bridge CTRunRef)runObj; CFRange runRange = CTRunGetStringRange(run); if ( runRange.location>=linkRange.location&&runRange.location<(linkRange.location+linkRange.length)) { //7 CGRect runBounds; CGFloat ascent; CGFloat descent; runBounds.size.width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, NULL); //8 runBounds.size.height = ascent + descent; CGFloat xOffset = CTLineGetOffsetForStringIndex(line1, CTRunGetStringRange(run).location, NULL); //9 runBounds.origin.x = Origins[lineIndex].x + xOffset ; runBounds.origin.y = Origins[lineIndex].y ; runBounds.origin.y=10000-runBounds.origin.y-runBounds.size.height; // NSLog(@"poing x: %f, y:%f",point.x,point.y); NSMutableDictionary * dic=[self.links objectAtIndex:linkIndex]; NSMutableArray * rects=[dic objectForKey:MatchParserRects]; [rects addObject:[NSValue valueWithCGRect:runBounds]]; //load the next image //12 if((runRange.location+runRange.length)>=(linkRange.location+linkRange.length)){ linkIndex++; if (linkIndex < [self.links count]) { nextLink = [self.links objectAtIndex: linkIndex]; linkRange = [[nextLink objectForKey: MatchParserRange] rangeValue]; }else{ _ctFrame=(__bridge id)frame; CFRelease(frame); CFRelease(path); CFRelease(framesetter); return; } } } } lineIndex++; } } _ctFrame=(__bridge id)frame; CFRelease(frame); CFRelease(path); CFRelease(framesetter); } -(void)matchLink:(NSString*)text attrString:(NSMutableAttributedString*)attStr offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link { _links=[[NSMutableArray alloc]init]; if(self.urlLink){ [self matchUrlLink:text attrString:attStr offset:offset link:link]; } // if(self.phoneLink){ // [self matchPhoneLink:text attrString:attStr offset:offset link:link]; // } if(self.mobieLink){ [self matchMobieLink:text attrString:attStr offset:offset link:link]; } [_links sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSDictionary * dic1=obj1; NSDictionary * dic2=obj2; NSRange range1=((NSValue *)[dic1 objectForKey:MatchParserRange]).rangeValue; NSRange range2=((NSValue *)[dic2 objectForKey:MatchParserRange]).rangeValue; if (range1.location]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil]; NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])]; for( NSTextCheckingResult * result in array){ if(link==nil){ CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL); NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil]; [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)]; CFRelease(fontRef); }else{ link(attrString1,NSMakeRange(result.range.location+offset,result.range.length)); } NSString * string=[source substringWithRange:result.range]; NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypeUrl,MatchParserLinkType,nil]; [_links addObject:dic]; } } //匹配手机号 -(void)matchMobieLink:(NSString*)source attrString:(NSMutableAttributedString*)attrString1 offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link { NSRegularExpression*regular=[[NSRegularExpression alloc]initWithPattern:@"(\\(86\\))?(13[0-9]|15[0-35-9]|18[0125-9])\\d{8}" options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive error:nil]; NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])]; for( NSTextCheckingResult * result in array){ if(link==nil){ CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL); NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil]; [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)]; CFRelease(fontRef); }else{ link(attrString1,NSMakeRange(result.range.location+offset,result.range.length)); } NSString * string=[source substringWithRange:result.range]; NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypeMobie,MatchParserLinkType,nil]; [_links addObject:dic]; } } //匹配座机号 -(void)matchPhoneLink:(NSString*)source attrString:(NSMutableAttributedString*)attrString1 offset:(int)offset link:(void(^)(NSMutableAttributedString*attrString,NSRange range))link { 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]; NSArray* array=[regular matchesInString:source options:0 range:NSMakeRange(0, [source length])]; for( NSTextCheckingResult * result in array){ 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]; NSString * string=[source substringWithRange:result.range]; NSUInteger numberOfMatches = [regular1 numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])]; if (numberOfMatches>0) { return; } if(link==nil){ CTFontRef fontRef=CTFontCreateWithName((__bridge CFStringRef)(self.font.fontName),self.font.pointSize,NULL); NSDictionary *attribute=[NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef,kCTFontAttributeName,(id)self.keyWorkColor.CGColor,kCTForegroundColorAttributeName,nil]; [attrString1 addAttributes:attribute range:NSMakeRange(result.range.location+offset,result.range.length)]; CFRelease(fontRef); }else{ link(attrString1,NSMakeRange(result.range.location+offset,result.range.length)); } NSMutableDictionary * dic=[NSMutableDictionary dictionaryWithObjectsAndKeys:string,MatchParserString,[NSValue valueWithRange:NSMakeRange(result.range.location+offset,result.range.length)],MatchParserRange,[[NSMutableArray alloc]init],MatchParserRects,MatchParserLinkTypePhone,MatchParserLinkType,nil]; [_links addObject:dic]; } } @end