[譯] iOS:NSScanner,一個(gè)陌生的條件判斷利器!


NSScanner官方文檔

NSScanner類(lèi)是一個(gè)類(lèi)簇的抽象父類(lèi),該類(lèi)簇為一個(gè)從NSString對(duì)象掃描值的對(duì)象提供了程序接口。

NSScanner對(duì)象把NSString 對(duì)象的的字符解釋和轉(zhuǎn)化成 number和string 類(lèi)型的值缴啡。在創(chuàng)建NSScanner對(duì)象的時(shí)候?yàn)樗峙渥址?string )优构,當(dāng)你從NSScanner對(duì)象獲取內(nèi)容的時(shí)候,它會(huì)從頭到尾遍歷字符串(string)界牡。

由于類(lèi)簇的屬性簿寂, scanner對(duì)象并不是 NSScanner類(lèi)的實(shí)例,而是它一個(gè)私有子類(lèi)的實(shí)例宿亡。盡管scanner對(duì)象的類(lèi)是私有的陶耍,但是它的接口是公開(kāi)的(抽象父類(lèi)已經(jīng)聲明)。 NSScanner 的原始方法是string和Configuring a Scanner方法下面列舉的所有的方法她混。

在 NSScanner 對(duì)象掃描字符串的時(shí)候烈钞,你可以通過(guò)設(shè)置屬性charactersToBeSkipped忽略某些字符。在掃描字符串之前坤按,那些位于忽略字符集中的字符將會(huì)被跳過(guò)毯欣。默認(rèn)的忽略字符是空格回車(chē)字符。

可以通過(guò)[[scanner string] substringFromIndex:[scanner scanLocation]]獲取未掃描的字符串臭脓。

創(chuàng)建 Scanner對(duì)象

+ (instancetype)scannerWithString:(NSString *)aString

+ (id)localizedScannerWithString:(NSString *)aString

- (instancetype)initWithString:(NSString *)aString
  • scannerWithString酗钞,返回值是 掃描過(guò)aString字符串的NSScanner 對(duì)象,該方法通過(guò)調(diào)用initWithString設(shè)置掃描字符串;
  • localizedScannerWithString,返回值是 通過(guò)用戶(hù)默認(rèn)的 locale方式掃描字符串的NSScanner 對(duì)象来累,該方法也是通過(guò)調(diào)用initWithString設(shè)置掃描字符串;
  • initWithString砚作,返回值是NSScanner 對(duì)象,該對(duì)象通過(guò)掃描aString完成初始化

獲取Scanner的字符串

@property(readonly, copy) NSString *string

配置Scanner

@property NSUInteger scanLocation
@property BOOL caseSensitive
@property(copy) NSCharacterSet *charactersToBeSkipped
@property(retain) id locale
  • scanLocation,下次掃描開(kāi)始的位置嘹锁,如果該值超出了string的區(qū)域葫录,將會(huì)引起NSRangeException,該屬性在發(fā)生錯(cuò)誤后重新掃描時(shí)非常有用。
  • caseSensitive领猾,是否區(qū)分字符串中大小寫(xiě)的標(biāo)志米同。默認(rèn)為NO,注意:該設(shè)置不會(huì)應(yīng)用到被跳過(guò)的字符集摔竿。
  • charactersToBeSkipped,在掃描時(shí)被跳過(guò)的字符集面粮,默認(rèn)是空白格和回車(chē)鍵。被跳過(guò)的字符集優(yōu)先于掃描的字符集:例如一個(gè)scanner被跳過(guò)的字符集為空格继低,通過(guò)scanInt:去查找字符串中的整型數(shù)時(shí)熬苍,首先做的不是掃描,而是跳過(guò)空格袁翁,直到找到十進(jìn)制數(shù)據(jù)或者其他的字符柴底。在字符被掃描的時(shí)候钱磅,跳過(guò)功能就失效了。如果你掃描的字符和跳過(guò)的字符是一樣的似枕,結(jié)果將是未知的盖淡。被跳過(guò)的字符是一個(gè)唯一值,scanner不會(huì)將忽略大小寫(xiě)的功能應(yīng)用于它凿歼,也不會(huì)用這些字符做一些組合褪迟,如果在掃描字符換的時(shí)候你想忽略全部的元音字符,就要這么做(比如:將字符集設(shè)置成“AEIOUaeiou”};
  • locale,scanner 的locale對(duì)它從字符串中區(qū)分?jǐn)?shù)值產(chǎn)生影響答憔,它通過(guò)locale的十進(jìn)制分隔符區(qū)分浮點(diǎn)型數(shù)據(jù)的整數(shù)和小數(shù)部分味赃。一個(gè)沒(méi)有l(wèi)ocale的scanner用非定域值。新的scanner若沒(méi)有設(shè)置locale虐拓,使用默認(rèn)locale心俗。

掃描字符串

- (BOOL)scanCharactersFromSet:(NSCharacterSet *)scanSet   intoString:(NSString * _Nullable *)stringValue;
- (BOOL)scanUpToCharactersFromSet:(NSCharacterSet *)stopSet    intoString:(NSString * _Nullable *)stringValue;
- (BOOL)scanString:(NSString *)string  intoString:(NSString * _Nullable *)stringValue;
- (BOOL)scanUpToString:(NSString *)stopString   intoString:(NSString * _Nullable *)stringValue;
- (BOOL)scanDecimal:(NSDecimal *)decimalValue;
- (BOOL)scanDouble:(double *)doubleValue;
- (BOOL)scanFloat:(float *)floatValue;
- (BOOL)scanHexDouble:(double *)result;
- (BOOL)scanHexFloat:(float *)result;
- (BOOL)scanHexInt:(unsigned int *)intValue;
- (BOOL)scanHexLongLong:(unsigned long long *)result;
- (BOOL)scanInt:(int *)intValue;
- (BOOL)scanInteger:(NSInteger *)value;
- (BOOL)scanUnsignedLongLong:(unsigned long long *)unsignedLongLongValue;
@property(getter=isAtEnd, readonly) BOOL atEnd;
  • scanCharactersFromSet:intoString:掃描字符串中和NSCharacterSet字符集中匹配的字符,是按字符單個(gè)匹配的蓉驹,例如城榛,NSCharacterSet字符集為@"test123Dmo",scanner字符串為 @" 123test12Demotest"态兴,那么字符串中所有的字符都在字符集中狠持,所以指針指向的地址存儲(chǔ)的內(nèi)容為"123test12Demotest"

  • scanUpToCharactersFromSet:intoString:掃描字符串直到遇到NSCharacterSet字符集的字符時(shí)停止,指針指向的地址存儲(chǔ)的內(nèi)容為遇到跳過(guò)字符集字符之前的內(nèi)容

  • scanString:intoString:從當(dāng)前的掃描位置開(kāi)始掃描瞻润,判斷掃描字符串是否從當(dāng)前位置能掃描到和傳入字符串相同的一串字符喘垂,如果能掃描到就返回YES,指針指向的地址存儲(chǔ)的就是這段字符串的內(nèi)容。例如scanner的string內(nèi)容為123abc678,傳入的字符串內(nèi)容為abc绍撞,如果當(dāng)前的掃描位置為0正勒,那么掃描不到,但是如果將掃描位置設(shè)置成3傻铣,就可以?huà)呙璧搅恕?/p>

  • scanUpToString:intoString:從當(dāng)前的掃描位置開(kāi)始掃描章贞,掃描到和傳入的字符串相同字符串時(shí),停止矾柜,指針指向的地址存儲(chǔ)的是遇到傳入字符串之前的內(nèi)容阱驾。例如scanner的string內(nèi)容為123abc678,傳入的字符串內(nèi)容為abc,存儲(chǔ)的內(nèi)容為123

  • scanDecimal:掃描NSDecimal類(lèi)型的值怪蔑,有關(guān)NSDecimal類(lèi)型的值更多的信息可以查看
    NSDecimalNumber

  • scanDouble :掃描雙精度浮點(diǎn)型字符,溢出和非溢出都被認(rèn)為合法的浮點(diǎn)型數(shù)據(jù)丧荐。在溢出的情況下scanner將會(huì)跳過(guò)所有的數(shù)字缆瓣,所以新的掃描位置將會(huì)在整個(gè)浮點(diǎn)型數(shù)據(jù)的后面。double指針指向的地址存儲(chǔ)的數(shù)據(jù)為掃描出的值虹统,包括溢出時(shí)的HUGE_VAL或者 –HUGE_VAL弓坞,即未溢出時(shí)的0.0隧甚。

  • scanFloat:掃描單精度浮點(diǎn)型字符,具體內(nèi)容同scanDouble

  • scanHexDouble: 掃描雙精度的十六進(jìn)制類(lèi)型渡冻,溢出和非溢出都被認(rèn)為合法的浮點(diǎn)型數(shù)據(jù)戚扳。在溢出的情況下scanner將會(huì)跳過(guò)所有的數(shù)字,所以新的掃描位置將會(huì)在整個(gè)浮點(diǎn)型數(shù)據(jù)的后面族吻。double指針指向的地址存儲(chǔ)的數(shù)據(jù)為掃描出的值帽借,包括溢出時(shí)的HUGE_VAL或者 –HUGE_VAL,即未溢出時(shí)的0.0超歌。數(shù)據(jù)接收時(shí)對(duì)應(yīng)的格式為 %a 或%A 砍艾,雙精度十六進(jìn)制字符前面一定要加 0x或者 0X

  • scanHexInt 掃描十六進(jìn)制無(wú)符整型巍举,unsigned int指針指向的地址值為 掃描到的值脆荷,包含溢出時(shí)的UINT_MAX。

  • scanHexLongLong 同scanHexDouble

  • scanInt 掃描整型懊悯,溢出也被認(rèn)為是有效的整型蜓谋,int 指針指向的地址的值為掃描到的值,包含溢出時(shí)的INT_MAXINT_MIN炭分。

  • scanInteger 同scanInt

  • scanLongLong 掃描LongLong 型孤澎,溢出也被認(rèn)為是有效的整型,LongLong指針指向的地址的值為掃描到的值欠窒,包含溢出時(shí)的LLONG_MAXLLONG_MIN覆旭。

實(shí)例:

#import <Foundation/Foundation.h>

@interface ConditionJudgmentController : NSObject
//輸入框中只能輸入數(shù)字和小數(shù)點(diǎn),且小數(shù)點(diǎn)只能輸入一位岖妄,參數(shù)number 可以設(shè)置小數(shù)的位數(shù)型将,該函數(shù)在-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string調(diào)用;
+(BOOL)isValidAboutInputText:(UITextField *)textfield shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string  decimalNumber: (NSInteger) number;
@end
#import "ConditionJudgmentController.h"

@implementation ConditionJudgmentController


+(BOOL)isValidAboutInputText:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string decimalNumber:(NSInteger)number{

    NSScanner      *scanner    = [NSScanner scannerWithString:string];
    NSCharacterSet *numbers;
    NSRange         pointRange = [textField.text rangeOfString:@"."];
    if ( (pointRange.length > 0) && (pointRange.location < range.location  || pointRange.location > range.location + range.length) ){
        numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
    }else{
        numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789."];
    }
    if ( [textField.text isEqualToString:@""] && [string isEqualToString:@"."] ){
        return NO;
    }
    short remain = number; //保留 number位小數(shù)
    NSString *tempStr = [textField.text stringByAppendingString:string];
    NSUInteger strlen = [tempStr length];
    if(pointRange.length > 0 && pointRange.location > 0){ //判斷輸入框內(nèi)是否含有“.”荐虐。
        if([string isEqualToString:@"."]){ //當(dāng)輸入框內(nèi)已經(jīng)含有“.”時(shí)七兜,如果再輸入“.”則被視為無(wú)效。
            return NO;
        }
        if(strlen > 0 && (strlen - pointRange.location) > remain+1){ //當(dāng)輸入框內(nèi)已經(jīng)含有“.”福扬,當(dāng)字符串長(zhǎng)度減去小數(shù)點(diǎn)前面的字符串長(zhǎng)度大于需要要保留的小數(shù)點(diǎn)位數(shù)腕铸,則視當(dāng)次輸入無(wú)效。
            return NO;
        }
    }
    NSRange zeroRange = [textField.text rangeOfString:@"0"];
    if(zeroRange.length == 1 && zeroRange.location == 0){ //判斷輸入框第一個(gè)字符是否為“0”
        if(![string isEqualToString:@"0"] && ![string isEqualToString:@"."] && [textField.text length] == 1){ //當(dāng)輸入框只有一個(gè)字符并且字符為“0”時(shí)铛碑,再輸入不為“0”或者“.”的字符時(shí)狠裹,則將此輸入替換輸入框的這唯一字符。
            textField.text = string;
            return NO;
        }else{
            if(pointRange.length == 0 && pointRange.location > 0){ //當(dāng)輸入框第一個(gè)字符為“0”時(shí)汽烦,并且沒(méi)有“.”字符時(shí)涛菠,如果當(dāng)此輸入的字符為“0”,則視當(dāng)此輸入無(wú)效。
                if([string isEqualToString:@"0"]){
                    return NO;
                }
            }
        }
    }
    NSString *buffer;
    if ( ![scanner scanCharactersFromSet:numbers intoString:&buffer] && ([string length] != 0) ){
        return NO;
    }else{
        return YES;
    }
}

@end

注意:上面的方法要結(jié)合UITextField的代理方法使用

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    return [ConditionJudgmentController isValidAboutInputText:textField shouldChangeCharactersInRange:range replacementString:string decimalNumber:3];
}

結(jié)束語(yǔ):
平時(shí)讀者在進(jìn)行條件判斷時(shí)俗冻,可能使用正則表達(dá)式或者用if語(yǔ)句比較多一點(diǎn)礁叔,其實(shí)NSScanner類(lèi)為我們提供了一個(gè)非常好的方式進(jìn)行判斷。把它們結(jié)合起來(lái)使用迄薄,可以獲得更好的效果琅关。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市讥蔽,隨后出現(xiàn)的幾起案子涣易,更是在濱河造成了極大的恐慌,老刑警劉巖勤篮,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件都毒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碰缔,警方通過(guò)查閱死者的電腦和手機(jī)账劲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)金抡,“玉大人瀑焦,你說(shuō)我怎么就攤上這事」8危” “怎么了榛瓮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)巫击。 經(jīng)常有香客問(wèn)我禀晓,道長(zhǎng),這世上最難降的妖魔是什么坝锰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任粹懒,我火速辦了婚禮,結(jié)果婚禮上顷级,老公的妹妹穿的比我還像新娘凫乖。我一直安慰自己,他們只是感情好弓颈,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布帽芽。 她就那樣靜靜地躺著,像睡著了一般翔冀。 火紅的嫁衣襯著肌膚如雪导街。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,156評(píng)論 1 308
  • 那天橘蜜,我揣著相機(jī)與錄音菊匿,去河邊找鬼付呕。 笑死计福,一個(gè)胖子當(dāng)著我的面吹牛跌捆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播象颖,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼佩厚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了说订?” 一聲冷哼從身側(cè)響起抄瓦,我...
    開(kāi)封第一講書(shū)人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陶冷,沒(méi)想到半個(gè)月后钙姊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埂伦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年煞额,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沾谜。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膊毁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出基跑,到底是詐尸還是另有隱情婚温,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布媳否,位于F島的核電站栅螟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏篱竭。R本人自食惡果不足惜力图,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望室抽。 院中可真熱鬧搪哪,春花似錦、人聲如沸坪圾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)兽泄。三九已至漓概,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間病梢,已是汗流浹背胃珍。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工梁肿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人觅彰。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓吩蔑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親填抬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子烛芬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容