搜索

在一个字符串中搜索子字符串

  • 最灵活的方法




1




​- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange locale:(NSLocale *)locale​



格式化字符串
  • 3个方法




1


2


3




​-initWithFormat:​


​-initWithFormat:arguments:​


​+stringWithFormat:​



整数
  • 可以同时工作在32位和64位的




1


2


3




​uint64_t p = 2305843009213693951;​


​NSString *s = [NSString stringWithFormat:@​​​​"The ninth Mersenne prime is %llu"​​​​, (unsigned long long) p];​


​// "The ninth Mersenne prime is 2305843009213693951"​



Modifier

d, i

o, u, x, X

hh

signed char

unsigned char

h

short

unsigned short

(none)

int

unsigned int

l(ell)

long

unsigned long

j

intmax_t

uintmax_t

t

ptrdiff_t

 

z

 

size_t

  • 转换规则




1


2


3


4


5




​int m = -150004021;​


​uint n = 150004021U;​


​NSString *s = [NSString stringWithFormat:@​​​​"d:%d i:%i o:%o u:%u x:%x X:%X"​​​​, m, m, n, n, n, n];​


​// "d:-150004021 i:-150004021 o:1074160465 u:150004021 x:8f0e135 X:8F0E135"​


​//o是八进制​



  • 设置最小字段宽度和最小数字位数




1


2


3


4


5


6




​int m = 42;​


​NSString *s = [NSString stringWithFormat:@​​​​"'%4d' '%-4d' '%+4d' '%4.3d' '%04d'"​​​​, m, m, m, m, m];​


​// "[ 42] [42 ] [ +42] [ 042] [0042]"​


​m = -42;​


​NSString *s = [NSString stringWithFormat:@​​​​"'%4d' '%-4d' '%+4d' '%4.3d' '%04d'"​​​​, m, m, m, m, m];​


​// "[ -42] [-42 ] [ -42] [-042] [-042]"​



  • %p可打印指针,和%#x不同的是它可以同时在32位和64位执行
浮点数
  • 使用%f和%g




1


2


3


4


5




​double v[5] = {12345, 12, 0.12, 0.12345678901234, 0.0000012345678901234};​


​NSString *s = [NSString stringWithFormat:@​​​​"%g %g %g %g %g"​​​​, v[0], v[1], v[2], v[3], v[4]];​


​// "12345 12 0.12 0.123457 1.23457e-06"​


​NSString *s = [NSString stringWithFormat:@​​​​"%f %f %f %f %f"​​​​, v[0], v[1], v[2], v[3], v[4]];​


​// "12345.000000 12.000000 0.120000 0.123457 0.000001"​



多行文字
  • 使用 来




1


2


3


4


5


6


7


8


9


10




​NSString *limerick = @​​​​"A lively young damsel named Menzies​


​"​


​@​​​​"Inquired: «Do you know what this thenzies?»​


​"​


​@​​​​"Her aunt, with a gasp,​


​"​


​@​​​​"Replied: "​​​​It​​​​'s a wasp,​


​"​


​@"And you'​​​​re holding the end where the stenzies.​


​";​



  • 等价写法




1


2


3


4


5


6




​NSString *limerick = @​​​​"A lively young damsel named Menzies​


​Inquired: «Do you know what this thenzies?»​


​Her aunt, with a gasp,​


​Replied: "​​​​It​​​​'s a wasp,​


​And you'​​​​re holding the end where the stenzies.​


​";​



更简洁的方法




1




​NSString * string = @​​​​"The man "​​ ​​@​​​​"who knows everything "​​ ​​@​​​​"learns nothing"​​ ​​@​​​​"."​​​​;​



替换字符串
  • NSMutableString的四个方法




1


2


3


4




​-deleteCharactersInRange:​


​-insertString:atIndex:​


​-replaceCharactersInRange:withString:​


​-replaceOccurrencesOfString:withString:options:range:​



NSString的方法




1


2


3




​-stringByReplacingOccurrencesOfString:withString:​


​-stringByReplacingOccurrencesOfString:withString:options:range:​


​-stringByReplacingCharactersInRange:withString:​



NSMutableString不会创建新字符串,性能会好点




1


2


3


4


5


6


7




​NSMutableString *string; ​​​​// 假设我们已经有了一个名为 string 的字符串​


​// 现在要去掉它的一个前缀,做法如下:​


​NSString *prefix = @​​​​"WeDon’tWantThisPrefix"​


​NSRange r = [string rangeOfString:prefix options:NSAnchoredSearch range:NSMakeRange(0, string.length) locale:nil];​


​if​​ ​​(r.location != NSNotFound) {​


​[string deleteCharactersInRange:r];​


​}​



连接字符串




1


2




​NSArray *names = @[​​​​"Hildr"​​​​, @​​​​"Heidrun"​​​​, @​​​​"Gerd"​​​​, @​​​​"Guðrún"​​​​, @​​​​"Freya"​​​​, @​​​​"Nanna"​​​​, @​​​​"Siv"​​​​, @​​​​"Skaði"​​​​, @​​​​"Gróa"​​​​];​


​NSString *result = [names componentsJoinedByString:@​​​​", "​​​​];​



字符串解析

正则表达式




1


2


3


4


5


6


7


8


9


10




​NSError *error = nil;​


​NSString *pattern = @​​​​"(\w+) = #(\p{Hex_Digit}{6})"​​​​;​


​NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern​


​options:0​


​error:&error];​


​NSTextCheckingResult *result = [expression firstMatchInString:string​


​options:0​


​range:NSMakeRange(0, string.length)];​


​NSString *key = [string substringWithRange:[result rangeAtIndex:1]];​


​NSString *value = [string substringWithRange:[result rangeAtIndex:2]];​



将字符串分解成数组,使用componentsSeparatedByString:这个方法,或者 enumerateSubstringsInRange:options:usingBlock:。如果是按照行来进行分解可以使用option这个参数 传NSStringEnumerationByLines




1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19




​NSString *input = @“​


​backgroundColor = ​​​​#ff0000​


​textColor = ​​​​#0000ff​


​"​


​NSString *pattern = @"​​​​(\w+) = ​​​​#([\da-f]{6})";​


​NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:pattern​


​options:0​


​error:NULL];​


​NSArray *lines = [input componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];​


​NSMutableDictionary *result = [NSMutableDictionary dictionary];​


​for​​ ​​(NSString *line ​​​​in​​ ​​lines) {​


​NSTextCheckingResult *textCheckingResult = [expression firstMatchInString:line​


​options:0​


​range:NSMakeRange(0, line.length)];​


​NSString* key = [line substringWithRange:[textCheckingResult rangeAtIndex:1]];​


​NSString* value = [line substringWithRange:[textCheckingResult rangeAtIndex:2]];​


​result[key] = value;​


​}​


​return​​ ​​result;​



扫描

  • NSScanner




1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22




​NSScanner *scanner = [NSScanner scannerWithString:string];​


​//默认情况下,扫描器会跳过所有空格符和换行符。但这里我们只希望跳过空格符​


​scanner.charactersToBeSkipped = [NSCharacterSet whitespaceCharacterSet];​


​//定义一个十六进制字符集​


​NSCharacterSet *hexadecimalCharacterSet =​


​[NSCharacterSet characterSetWithCharactersInString:@​​​​"0123456789abcdefABCDEF"​​​​];​


 


​NSMutableDictionary *result = [NSMutableDictionary dictionary];​


​while​​ ​​(!scanner.isAtEnd) {​


​NSString *key = nil;​


​NSString *value = nil;​


​NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];​


​BOOL didScan = [scanner scanCharactersFromSet:letters intoString:&key] &&​


​[scanner scanString:@​​​​"="​​ ​​intoString:NULL] &&​


​[scanner scanString:@​​​​"#"​​ ​​intoString:NULL] &&​


​[scanner scanCharactersFromSet:hexadecimalCharacterSet intoString:&value] &&​


​value.length == 6;​


​result[key] = value;​


​[scanner scanCharactersFromSet:[NSCharacterSet newlineCharacterSet]​


​intoString:NULL]; ​​​​// 继续扫描下一行​


​}​


​return​​ ​​result;​



解析器

  • 设计一个能够用(100,0,255)或者#ff0000这样的字符来定义颜色的方法。




1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


25


26


27


28


29


30


31


32


33


34


35


36


37


38


39


40


41


42


43


44


45


46


47


48


49


50


51


52


53


54


55


56


57


58


59


60




​- (NSDictionary *)parse:(NSString *)string error:(NSError **)error​


​{​


​self.scanner = [NSScanner scannerWithString:string];​


​self.scanner.charactersToBeSkipped = [NSCharacterSet whitespaceCharacterSet];​


 


​NSMutableDictionary *result = [NSMutableDictionary dictionary];​


​NSCharacterSet *letters = [NSCharacterSet letterCharacterSet]​


​while​​ ​​(!self.scanner.isAtEnd) {​


​NSString *key = nil;​


​UIColor *value = nil;​


​BOOL didScan = [self.scanner scanCharactersFromSet:letters intoString:&key] &&​


​[self.scanner scanString:@​​​​"="​​ ​​intoString:NULL] &&​


​[self scanColor:&value];​


​result[key] = value;​


​[self.scanner scanCharactersFromSet:[NSCharacterSet newlineCharacterSet]​


​intoString:NULL]; ​​​​// 继续扫描下一行​


​}​


​}​


 


​- (BOOL)scanColor:(UIColor **)out​


​{​


​return​​ ​​[self scanHexColorIntoColor:out] || [self scanTupleColorIntoColor:out];​


​}​


 


​//扫描设置#ff0000这样的​


​- (BOOL)scanHexColorIntoColor:(UIColor **)out​


​{​


​NSCharacterSet *hexadecimalCharacterSet =​


​[NSCharacterSet characterSetWithCharactersInString:@​​​​"0123456789abcdefABCDEF"​​​​];​


​NSString *colorString = NULL;​


​if​​ ​​([self.scanner scanString:@​​​​"#"​​ ​​intoString:NULL] &&​


​[self.scanner scanCharactersFromSet:hexadecimalCharacterSet​


​intoString:&colorString] &&​


​colorString.length == 6) {​


​*out = [UIColor colorWithHexString:colorString];​


​return​​ ​​YES;​


​}​


​return​​ ​​NO;​


​}​


 


​- (BOOL)scanTupleColorIntoColor:(UIColor **)out​


​{​


​NSInteger red, green, blue = 0;​


​BOOL didScan = [self.scanner scanString:@​​​​"("​​ ​​intoString:NULL] &&​


​[self.scanner scanInteger:&red] &&​


​[self.scanner scanString:@​​​​","​​ ​​intoString:NULL] &&​


​[self.scanner scanInteger:&green] &&​


​[self.scanner scanString:@​​​​","​​ ​​intoString:NULL] &&​


​[self.scanner scanInteger:&blue] &&​


​[self.scanner scanString:@​​​​")"​​ ​​intoString:NULL];​


​if​​ ​​(didScan) {​


​*out = [UIColor colorWithRed:(CGFloat)red/255.​


​green:(CGFloat)green/255.​


​blue:(CGFloat)blue/255.​


​alpha:1];​


​return​​ ​​YES;​


​} ​​​​else​​ ​​{​


​return​​ ​​NO;​


​}​


​}​



符号化处理

先进星扫描,使用NSScanner来解析这个表达式




1


2




​myView.left = otherView.right * 2 + 10​


​viewController.view.centerX + myConstant <= self.view.centerX​





1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


21


22


23


24


25


26


27


28


29


30


31


32


33


34


35




​NSScanner *scanner = [NSScanner scannerWithString:contents];​


​NSMutableArray *tokens = [NSMutableArray array];​


​while​​ ​​(![scanner isAtEnd]) {​


​for​​ ​​(NSString *operator ​​​​in​​ ​​@[@​​​​"="​​​​, @​​​​"+"​​​​, @​​​​"*"​​​​, @​​​​">="​​​​, @​​​​"<="​​​​, @​​​​"."​​​​]) {​


​if​​ ​​([scanner scanString:operator intoString:NULL]) {​


​[tokens addObject:operator];​


​}​


​}​


​}​


​//接下来识别非符号的只包含字母的string​


​NSString *result = nil;​


​if​​ ​​([scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet]​


​intoString:&result]) {​


​[tokens addObject:result];​


​}​


 


​//NSScanner有scanDouble:来扫描double​


​double doubleResult = 0;​


​if​​ ​​([scanner scanDouble:&doubleResult]) {​


​[tokens addObject:@(doubleResult)];​


​}​


​//完成后用将需要解析的表达式放入试试​


​NSString* example = @​​​​"myConstant = 100​


​"​


​@​​​​"​


​myView.left = otherView.right * 2 + 10​


​"​


​@​​​​"viewController.view.centerX + myConstant <= self.view.centerX"​​​​;​


​NSArray *result = [self.scanner tokenize:example];​


​NSArray *expected = @[@​​​​"myConstant"​​​​, @​​​​"="​​​​, @100, @​​​​"myView"​​​​, @​​​​"."​​​​, @​​​​"left"​​​​,​


​@​​​​"="​​​​, @​​​​"otherView"​​​​, @​​​​"."​​​​, @​​​​"right"​​​​, @​​​​"*"​​​​, @2, @​​​​"+"​​​​,​


​@10, @​​​​"viewController"​​​​, @​​​​"."​​​​, @​​​​"view"​​​​, @​​​​"."​​​​,​


​@​​​​"centerX"​​​​, @​​​​"+"​​​​, @​​​​"myConstant"​​​​, @​​​​"<="​​​​, @​​​​"self"​​​​,​


​@​​​​"."​​​​, @​​​​"view"​​​​, @​​​​"."​​​​, @​​​​"centerX"​​​​];​


​XCTAssertEqualObjects(result, expected);​



进行语法解析,需要语法分析库描述我们的语言。下面代码就是为那个布局约束语言写的解析语法,用的扩展的巴科斯:




1


2


3


4


5


6


7


8




​constraint = expression comparator expression​


​comparator = ​​​​"="​​ ​​| ​​​​">="​​ ​​| ​​​​"<="​


​expression = keyPath ​​​​"."​​ ​​attribute addMultiplier addConstant​


​keyPath = identifier | identifier ​​​​"."​​ ​​keyPath​


​attribute = ​​​​"left"​​ ​​| ​​​​"right"​​ ​​| ​​​​"top"​​ ​​| ​​​​"bottom"​​ ​​| ​​​​"leading"​​ ​​| ​​​​"trailing"​​ ​​| ​​​​"width"​​ ​​| ​​​​"height"​​ ​​| ​​​​"centerX"​​ ​​| ​​​​"centerY"​​ ​​| ​​​​"baseline"​


​addMultiplier = ​​​​"*"​​ ​​atom​


​addConstant = ​​​​"+"​​ ​​atom​


​atom = number | identifier​



还有很多Objective-C的语法解析,更多的可以在CocoaPods上找到:​



1


2


3


4


5


6


7


8


9


10


11


12


13


14




​NSString* grammarString = [@[​


​@​​​​"Atom ::= num@'Number' | ident@'Identifier';"​​​​,​


​@​​​​"Constant ::= name@'Identifier' '=' value@<Atom>;"​​​​,​


​@​​​​"Relation ::= '=' | '>=' | '<=';"​​​​,​


​@​​​​"Attribute ::= 'left' | 'right' | 'top' | 'bottom' | 'leading' | 'trailing' | 'width' | 'height' | 'centerX' | 'centerY' | 'baseline';"​​​​,​


​@​​​​"Multiplier ::= '*' num@'Number';"​​​​,​


​@​​​​"AddConstant ::= '+' num@'Number';"​​​​,​


​@​​​​"KeypathAndAttribute ::= 'Identifier' '.' <AttributeOrRest>;"​​​​,​


​@​​​​"AttributeOrRest ::= att@<Attribute> | 'Identifier' '.' <AttributeOrRest>;"​​​​,​


​@​​​​"Expression ::= <KeypathAndAttribute> <Multiplier>? <AddConstant>?;"​​​​,​


​@​​​​"LayoutConstraint ::= lhs@<Expression> rel@<Relation> rhs@<Expression>;"​​​​,​


​@​​​​"Rule ::= <Atom> | <LayoutConstraint>;"​​​​,​


​] componentsJoinedByString:@​​​​"​


​"​​​​];​



一个规则匹配后解析器就找到同样名称的类




1


2


3


4


5


6


7




​- (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree​


​NSString *ruleName = syntaxTree.rule.name;​


​if​​ ​​([ruleName isEqualToString:@​​​​"Attribute"​​​​]) {​


​return​​ ​​self.layoutAttributes[[[syntaxTree childAtIndex:0] keyword]];​


​}​


​...​


​}​





1




​viewController.view.centerX + 20 <= self.view.centerX * 0.5​



可以得到如下结果,方便转换成NSLayoutConstraint对象




1


2


3


4


5


6


7


8


9




​(<Expression: self.keyPath=(viewController, view),​


​self.attribute=9,​


​self.multiplier=1,​


​self.constant=20>​


​-1​


​<Expression: self.keyPath=(self, view),​


​self.attribute=9,​


​self.multiplier=0.5,​


​self.constant=0>)​



字符串的渲染

UILabel

  • label默认显示一行,如果设置numberOfLines为大于1的话可以显示指定行数,如果设置为0,则多少行都显示
  • attributedText属性可以显示富文本
  • label的font,textColor,textAlignment,shadowColor和shadowOffset属性可以改变外观。
  • 改变程序内所有Label的风格,可以使用[UILabel appearance]方法

UITextField

  • text field只限于单行
  • UITextfield实现了UITextInputTraits协议,这个协议需要指定键盘外观和操作等细节。比如显示什么键盘和返回按键响应等
  • 可以通过设置左右辅助视图,或者设置背景来自定义输入框风格了。

UITextView

TableView中显示动态文本

Table view的Delegate有个方法用来计算高度:tableView:heightForRowAtIndexPath:。自定义一个UITableViewCell的子类




1


2


3


4


5


6


7




​- (void)layoutSubviews​


​{​


​[​​​​super​​ ​​layoutSubviews];​


​self.textLabel.frame = CGRectInset(self.bounds,​


​MyTableViewCellInset,​


​MyTableViewCellInset);​


​}​



计算真实高度需要使用boundingRectWithSize:options:context: 这个方法




1


2


3


4


5


6


7


8


9


10


11


12




​- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath​


​{​


​CGFloat labelWidth = self.tableView.bounds.size.width - MyTableViewCellInset*2;​


​NSAttributedString *text = [self attributedBodyTextAtIndexPath:indexPath];​


​NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin |​


​NSStringDrawingUsesFontLeading;​


​CGRect boundingRect = [text boundingRectWithSize:CGSizeMake(labelWidth, CGFLOAT_MAX)​


​options:options​


​context:nil];​


 


​return​​ ​​(CGFloat) (ceil(boundingRect.size.height) + MyTableViewCellInset*2);​


​}​



使用Text Kit和NSAttributedString进行布局

先设置attributes




1


2


3


4


5


6


7


8


9


10


11


12




​CGFloat const fontSize = 15;​


 


​NSMutableDictionary *body1stAttributes = [NSMutableDictionary dictionary];​


​body1stAttributes[NSFontAttributeName] = [UIFont fontWithName:@​​​​"BodoniSvtyTwoITCTT-Book"​


​size:fontSize];​


​NSMutableParagraphStyle *body1stParagraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];​


​body1stParagraph.alignment = NSTextAlignmentJustified;​


​body1stParagraph.minimumLineHeight = fontSize + 3;​


​body1stParagraph.maximumLineHeight = body1stParagraph.minimumLineHeight;​


​body1stParagraph.hyphenationFactor = 0.97;​


​body1stAttributes[NSParagraphStyleAttributeName] = body1stParag​


​raph;​



这里字体为BodoniSvtyTwoITCTT,如果需要查看更多字体可以使用 +[UIFont familyNames]这个方法。为了得到字体的名字,可以使用 +[UIFont fontNamesForFamilyName:]。接下来创建段落的属性




1


2


3


4


5




​NSMutableDictionary *bodyAttributes = [body1stAttributes mutableCopy];​


​NSMutableParagraphStyle *bodyParagraph =​


​[bodyAttributes[NSParagraphStyleAttributeName] mutableCopy];​


​bodyParagraph.firstLineHeadIndent = fontSize;​


​bodyAttributes[NSParagraphStyleAttributeName] = bodyParagraph;​



装饰段落风格,使用装饰字体将文本居中对齐,装饰字符的前后加上空白段落




1


2


3


4


5


6


7


8




​NSMutableDictionary *ornamentAttributes = [NSMutableDictionary dictionary];​


​ornamentAttributes[NSFontAttributeName] = [UIFont fontWithName:@​​​​"BodoniOrnamentsITCTT"​


​size:36];​


​NSMutableParagraphStyle *ornamentParagraph = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];​


​ornamentParagraph.alignment = NSTextAlignmentCenter;​


​ornamentParagraph.paragraphSpacingBefore = fontSize;​


​ornamentParagraph.paragraphSpacing = fontSize;​


​ornamentAttributes[NSParagraphStyleAttributeName] = ornamentParagraph;​



显示数字表格table,表格布局示例




1


2


3


4


5


6


7


8


9


10


11


12




​NSCharacterSet *decimalTerminator = [NSCharacterSet​


​characterSetWithCharactersInString:decimalFormatter.decimalSeparator];​


​NSTextTab *decimalTab = [[NSTextTab alloc]​


​initWithTextAlignment:NSTextAlignmentCenter​


​location:100​


​options:@{NSTabColumnTerminatorsAttributeName:decimalTerminator}];​


​NSTextTab *percentTab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentRight​


​location:200​


​options:nil];​


​NSMutableParagraphStyle *tableParagraphStyle =​


​[[NSParagraphStyle defaultParagraphStyle] mutableCopy];​


​tableParagraphStyle.tabStops = @[decimalTab, percentTab];​



显示列表的属性设置如下




1


2


3


4


5


6


7


8


9


10




​NSMutableDictionary *listAttributes = [bodyAttributes mutableCopy];​


​NSMutableParagraphStyle *listParagraph =​


​[listAttributes[NSParagraphStyleAttributeName] mutableCopy];​


​listParagraph.headIndent = fontSize * 3;​


​listParagraph.firstLineHeadIndent = fontSize;​


​NSTextTab *listTab = [[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentNatural​


​location:fontSize * 3​


​options:nil];​


​listParagraph.tabStops = @[listTab];​


​listAttributes[NSParagraphStyleAttributeName] = listParagraph;​