[譯] 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ò)用戶默認(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,就可以掃描到了。

  • 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)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

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