iOS字符串 如何使用正則表達(dá)式解析,NSScanner掃描,設(shè)置和使用CoreParse解析器來(lái)解析處理自定義符號(hào)等內(nèi)容

搜索

在一個(gè)字符串中搜索子字符串

  • 最靈活的方法
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange locale:(NSLocale *)locale

格式化字符串

  • 3個(gè)方法
-initWithFormat:
-initWithFormat:arguments:
+stringWithFormat:

整數(shù)

  • 可以同時(shí)工作在32位和64位的
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
  • 轉(zhuǎn)換規(guī)則
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是八進(jìn)制
  • 設(shè)置最小字段寬度和最小數(shù)字位數(shù)
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不同的是它可以同時(shí)在32位和64位執(zhí)行

浮點(diǎn)數(shù)

  • 使用%f和%g
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"

多行文字

  • 使用\n來(lái)
NSString *limerick = @"A lively young damsel named Menzies\n"
@"Inquired: ?Do you know what this thenzies??\n"
@"Her aunt, with a gasp,\n"
@"Replied: "It's a wasp,\n"
@"And you're holding the end where the stenzies.\n";
  • 等價(jià)寫(xiě)法
NSString *limerick = @"A lively young damsel named Menzies\nInquired: ?Do you know what this thenzies??\nHer aunt, with a gasp,\nReplied: "It's a wasp,\nAnd you're holding the end where the stenzies.\n";
  • 更簡(jiǎn)潔的方法
NSString * string = @"The man " @"who knows everything " @"learns nothing" @".";

替換字符串

  • NSMutableString的四個(gè)方法
-deleteCharactersInRange:
-insertString:atIndex:
-replaceCharactersInRange:withString:
-replaceOccurrencesOfString:withString:options:range:
  • NSString的方法
-stringByReplacingOccurrencesOfString:withString:
-stringByReplacingOccurrencesOfString:withString:options:range:
-stringByReplacingCharactersInRange:withString:
  • NSMutableString不會(huì)創(chuàng)建新字符串,性能會(huì)好點(diǎn)
NSMutableString *string; // 假設(shè)我們已經(jīng)有了一個(gè)名為 string 的字符串
// 現(xiàn)在要去掉它的一個(gè)前綴,做法如下:
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];
}

連接字符串

NSArray *names = @["Hildr", @"Heidrun", @"Gerd", @"Guerún", @"Freya", @"Nanna", @"Siv", @"Skaei", @"Gróa(chǎn)"];
NSString *result = [names componentsJoinedByString:@", "];

字符串解析

正則表達(dá)式

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]];

將字符串分解成數(shù)組,使用componentsSeparatedByString:這個(gè)方法,或者enumerateSubstringsInRange:options:usingBlock:。如果是按照行來(lái)進(jìn)行分解可以使用option這個(gè)參數(shù)傳NSStringEnumerationByLines

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
NSScanner *scanner = [NSScanner scannerWithString:string];
//默認(rèn)情況下,掃描器會(huì)跳過(guò)所有空格符和換行符。但這里我們只希望跳過(guò)空格符
scanner.charactersToBeSkipped = [NSCharacterSet whitespaceCharacterSet];
//定義一個(gè)十六進(jìn)制字符集
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]; // 繼續(xù)掃描下一行
}
return result;

解析器

  • 設(shè)計(jì)一個(gè)能夠用(100,0,255)或者#ff0000這樣的字符來(lái)定義顏色的方法。
- (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]; // 繼續(xù)掃描下一行
     }
}

- (BOOL)scanColor:(UIColor **)out
{
     return [self scanHexColorIntoColor:out] || [self scanTupleColorIntoColor:out];
}

//掃描設(shè)置#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;
     }
}

符號(hào)化處理

先進(jìn)星掃描,使用NSScanner來(lái)解析這個(gè)表達(dá)式

myView.left = otherView.right * 2 + 10
viewController.view.centerX + myConstant <= self.view.centerX
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];
          }
     }
}
//接下來(lái)識(shí)別非符號(hào)的只包含字母的string
NSString *result = nil;
if ([scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet]
          intoString:&result]) {
     [tokens addObject:result];
}

//NSScanner有scanDouble:來(lái)掃描double
double doubleResult = 0;
if ([scanner scanDouble:&doubleResult]) {
     [tokens addObject:@(doubleResult)];
}
//完成后用將需要解析的表達(dá)式放入試試
NSString* example = @"myConstant = 100\n"
     @"\nmyView.left = otherView.right * 2 + 10\n"
     @"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);

進(jìn)行語(yǔ)法解析,需要語(yǔ)法分析庫(kù)描述我們的語(yǔ)言。下面代碼就是為那個(gè)布局約束語(yǔ)言寫(xiě)的解析語(yǔ)法,用的擴(kuò)展的巴科斯范式EBNF寫(xiě)法:

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的語(yǔ)法解析,更多的可以在CocoaPods上找到:http://cocoapods.org/?q=parse。比較好的就是CoreParse,地址:https://github.com/beelsebob/CoreParse,但是需要使用它支持的語(yǔ)法。下面就是CoreParse支持的格式:

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:@"\n"];

一個(gè)規(guī)則匹配后解析器就找到同樣名稱的類

- (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree
     NSString *ruleName = syntaxTree.rule.name;
     if ([ruleName isEqualToString:@"Attribute"]) {
          return self.layoutAttributes[[[syntaxTree childAtIndex:0] keyword]];
     }
...
}

完整的解析器代碼在:https://github.com/objcio/issue-9-string-parsing。里面有個(gè)解析類可以用來(lái)解析復(fù)雜的布局約束,如下:

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

可以得到如下結(jié)果,方便轉(zhuǎn)換成NSLayoutConstraint對(duì)象

(<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默認(rèn)顯示一行,如果設(shè)置numberOfLines為大于1的話可以顯示指定行數(shù),如果設(shè)置為0,則多少行都顯示
  • attributedText屬性可以顯示富文本
  • label的font,textColor,textAlignment,shadowColor和shadowOffset屬性可以改變外觀。
  • 改變程序內(nèi)所有Label的風(fēng)格,可以使用[UILabel appearance]方法

UITextField

  • text field只限于單行
  • UITextfield實(shí)現(xiàn)了UITextInputTraits協(xié)議,這個(gè)協(xié)議需要指定鍵盤(pán)外觀和操作等細(xì)節(jié)。比如顯示什么鍵盤(pán)和返回按鍵響應(yīng)等
  • 可以通過(guò)設(shè)置左右輔助視圖,或者設(shè)置背景來(lái)自定義輸入框風(fēng)格了。

UITextView

TableView中顯示動(dòng)態(tài)文本

Table view的Delegate有個(gè)方法用來(lái)計(jì)算高度:tableView:heightForRowAtIndexPath:。自定義一個(gè)UITableViewCell的子類

- (void)layoutSubviews
{
     [super layoutSubviews];
     self.textLabel.frame = CGRectInset(self.bounds,
          MyTableViewCellInset,
          MyTableViewCellInset);
}

計(jì)算真實(shí)高度需要使用boundingRectWithSize:options:context: 這個(gè)方法

- (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進(jìn)行布局

先設(shè)置attributes

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]這個(gè)方法。為了得到字體的名字,可以使用 +[UIFont fontNamesForFamilyName:]。接下來(lái)創(chuàng)建段落的屬性

NSMutableDictionary *bodyAttributes = [body1stAttributes mutableCopy];
NSMutableParagraphStyle *bodyParagraph =
     [bodyAttributes[NSParagraphStyleAttributeName] mutableCopy];
bodyParagraph.firstLineHeadIndent = fontSize;
bodyAttributes[NSParagraphStyleAttributeName] = bodyParagraph;

裝飾段落風(fēng)格,使用裝飾字體將文本居中對(duì)齊,裝飾字符的前后加上空白段落

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;

顯示數(shù)字表格table,表格布局示例

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];

顯示列表的屬性設(shè)置如下

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;

字符串本地化

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • iOS字符串處理筆記(正則表達(dá)式、NSScanner掃描、CoreParse解析器) http://www.jco...
    kakukeme閱讀 1,041評(píng)論 0 51
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,578評(píng)論 19 139
  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,679評(píng)論 0 4
  • 一、字符串在C#中,字符串是一系列不可修改的Unicode字符,創(chuàng)建字符串后,就不能修改它。要?jiǎng)?chuàng)建字符串,最常用的...
    CarlDonitz閱讀 1,386評(píng)論 0 2
  • 微電影劇本《平凡之路》 主題曲:《平凡之路》 角色:旻(女) 茹(女) 部長(zhǎng) 同學(xué) 故事梗概:高中同班同學(xué)的...
    f24762f9ac0b閱讀 445評(píng)論 0 1

友情鏈接更多精彩內(nèi)容