NSScanner 使用实例

NSScanner是用于扫描字符串内容的工具,其scanLocation属性至关重要。主要方法包括scanString:intoString:和scanUpToString:intoString:。在实际应用中,可以利用NSScanner查找并提取字符串中的特定信息,如从产品描述中解析出包装规格和数量。通过设置skipCharactersToBeSkipped,可以忽略特定字符。示例代码展示了如何从产品描述中提取名称和价格。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NSScanner的应用实例

NSScanner是系统提供的一个可以扫描字符串中内容的方法,由于location这个属性的特性,NSScanner常常配合循环使用

先看看NSScanner的几个基本属性

@property (readonly, copy) NSString *string; //通过这个属性可以用getter方法导出scanner初始化时设置string
@property NSUInteger scanLocation; //最重要的属性,代表scanner目前扫描的位置,可以使用setter方法
@property (nullable, copy) NSCharacterSet *charactersToBeSkipped; //扫描时需要跳过的字符
@property BOOL caseSensitive; //忽略大小写区别

NSScanner的常用方法
1.scanString: intoString:
在scanner中搜索目标字符串,如果第一个字符和目标字符串相等,return 1,如果第一个字符和目标字符串不相等,return 0.intoString为返回的目标字符串(也可以设置为nil),scanner.scanLocation值变成目标字符串后面一位
2.scanUpToString: intoString:
在scanner中搜索目标字符串,如果第一个字符和目标字符串相等,return 0,intoString为返回的目标字符串(也可以设置为nil),scanner.scanLocation值保留目标字符串前面一位

Scanner的实际应用

#import "NSString+Scanner.h"  //创建了一个NSString的Category,方便方法的调用

@implementation NSString (Scanner)
//1.查找某个string里是否含有int值
- (BOOL)isPureInt
{
    NSScanner *scanner = [[NSScanner alloc] initWithString:self];
    int intValue;
    return [scanner scanInt:&intValue] && [scanner isAtEnd];
}

//2.查找给定String中所含有的全部浮点数值
- (void)scanFloatValue
{
    NSScanner *scanner = [[NSScanner alloc] initWithString:self];
    float floatValue;
    while (![scanner isAtEnd])
    {
        if ([scanner scanFloat:&floatValue])
        {
            NSLog(@"floatValue = %.2f",floatValue);
        }
        scanner.scanLocation++;//由于scanLocation的特殊机制,这里需要注意的是如果最后字符串最后一位是浮点数类型的话会crash,在最后一位拼接上一个字母就可以正常运行了.
    }
}

在main. m中可以用NSString的对象直接调用方法

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "NSString+Scanner.h"
int main(int argc, char * argv[]) {
NSString *intString = @"211231233423523511";
    if ([intString isPureInt])
    {
        NSLog(@"是纯int");
    }
    else
    {
        NSLog(@"不是纯int");
    }
//输出:是纯int
    NSString *floatString = @"1.5,2.8,-0.99,pre hour;";
    [floatString scanFloatValue];
    //输出:floatValue = 1.50
    //    floatValue = 2.80
    //    floatValue = -0.99
}
3.假设有个TXT格式的文本:
<abc1>fwerwer
<abc2>asfdapeirjqpierj;;
wwr<abc3>
<aa>
想要从中提取出<>内的内容
代码如下:
    NSString *tmp;
    NSArray *lines;
    lines = [[NSString stringWithContentsOfFile:@"/Users/linjiaqiao/Documents/Now/Lesson-OC-04/Lesson-OC-04/安装包密码.txt" encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByString:@"\n"];
    NSLog(@"lines = %@",lines);
    NSEnumerator *nse = [lines objectEnumerator];//创建一个枚举器
    // 读取<>里的内容
    while(tmp = [nse nextObject])
    {
        NSString *test1 = nil;
        NSString *test2 = nil;
        NSString *stringBetweenBrackets = nil;
        NSScanner *scanner = [NSScanner scannerWithString:tmp];
        [scanner scanUpToString:@"<" intoString:&test1];   // "<"之前的字符串装入test1中,scanLocation在"<"前的位置 如果第一位就是"<"的话返回值为0
        [scanner scanString:@"<" intoString:&test2];          // "<"装入test2中,scanLocation在"<"后的位置 如果第一位是"<"的话返回值为1
        [scanner scanUpToString:@">" intoString:&stringBetweenBrackets];
        NSLog(@"<>内的内容 = %@",[stringBetweenBrackets description]);
        NSLog(@"test1 = %@",test1);
        NSLog(@"test2 = %@",test2);
//输出结果:
2016-02-16 17:12:40.667 Lesson-OC-04[6530:503881] <>内的内容 = abc1
2016-02-16 17:12:40.667 Lesson-OC-04[6530:503881] test1 = (null)
2016-02-16 17:12:40.668 Lesson-OC-04[6530:503881] test2 = <
2016-02-16 17:12:40.668 Lesson-OC-04[6530:503881] <>内的内容 = abc2
2016-02-16 17:12:40.668 Lesson-OC-04[6530:503881] test1 = (null)
2016-02-16 17:12:40.669 Lesson-OC-04[6530:503881] test2 = <
2016-02-16 17:12:40.669 Lesson-OC-04[6530:503881] <>内的内容 = abc3
2016-02-16 17:12:40.669 Lesson-OC-04[6530:503881] test1 = wwr
2016-02-16 17:12:40.670 Lesson-OC-04[6530:503881] test2 = <
2016-02-16 17:12:40.670 Lesson-OC-04[6530:503881] <>内的内容 = aa
2016-02-16 17:12:40.670 Lesson-OC-04[6530:503881] test1 = (null)
2016-02-16 17:12:40.670 Lesson-OC-04[6530:503881] test2 = <

可以看出每次循环先要用scanUpToString: intoString:方法找出@"<",此时location在@"<"前,再用scanString: intoString:方法使location在@"<"后,最后再次使用scanUpToString: intoString:方法把从location位置到@">"前的字符串都提取出来.

NSScanner的扫描操作从上次扫描的位置开始,并且继续往后扫描直到指定的内容出现为止(如果有的话)。以字符串“137 small cases of bananas”为例,在扫描完一个整数之后,scanner的位置将变为3,也即数字后面的空格处。通常,你会继续扫描并跳过你不关心的字符。那么你可以用setScanLocation:方法跳过某几个字符(也可以用这个方法在发生某些错误后,重新开始扫描字符串的某部分)。如果你想跳过某种特殊的字符集中的字符时,可以使用setCharactersToBeSkipped:方法。scanner在任何扫描操作时会跳过空白字符之后才开始。但是当它找到一个可以扫描的字符时,它会用全部字符去和指定内容匹配。scanner默认情况下会忽略空白字符和换行符。注意,对于忽略字符,总是大小写敏感的。例如要忽略所有原音字母,你必须使用“AEIOUaeiou”,而不能仅仅是“AEIOU”或“aeiou”。 如果你想获取当前位置的某个字符串的内容,可以使用scanUpToString:intoString:方法(如果你不想保留这些字符,可以传递一个NULL给第2个参数)。
例1 以下列字符串为例:
137 small cases of bananas
下面的代码,可以从字符串中找出包装规格(small cases)和包装数量(137)。


    NSString *bananas = @"137 small cases of bananas";
    NSString *separatorString = @" of";
    NSScanner *aScanner = [NSScanner scannerWithString:bananas];
    NSInteger anInteger;
    [aScanner scanInteger:&anInteger];
    NSLog(@"%ld",anInteger);  //137
    NSString *container;
    NSLog(@"此时scanLocatoin = %ld",aScanner.scanLocation);  //此时scanLocatoin = 3
    [aScanner scanUpToString:separatorString intoString:&container];//upToString 代表扫描碰到什么字符串结束,location在此字符串前
    NSLog(@"container = %@",container);
    NSLog(@"此时scanLocatoin = %ld",aScanner.scanLocation);  //此时scanLocatoin = 15

查找字符串separatorString为“ of”关系重大。默认scanner会忽略空白字符,因此在数字137后面的空格被忽略。但是当scanner从空格后面的字符开始时,所有的字符都被加到了输出字符串中,一直到遇到搜索字符串(“of”)。
如果搜索字符串是“of”(前面没空格),container的第一个值应该是“smallcases ”(后面有个空格);如果搜索字符串是“ of”(前面有空格),则container的第1个值是“small cases”(后面无空格)。
在扫描到指定字符串(搜索字符串)之后,scanner的位置指向了该字符串开始处。如果你想继续扫描该字符串之后的字符,必须先扫描指定字符串(搜索字符串)。下列代码演示了如何跳过搜索字串并取得产品类型。注意我们使用了substringFromIndex:,等同于继续扫描直到整个字符串的末尾。

NSString *product;
    product = [[aScanner string] substringFromIndex:[aScanner scanLocation]];//用product接收未被扫描的余下的字符串
    NSLog(@"%ld",[aScanner scanLocation]);
    NSLog(@"product = %@",product);

例2 假设你有如下字符串:
Product: Acme Potato Peeler; Cost: 0.98 73
Product: Chef Pierre Pasta Fork; Cost: 0.75 19
Product: Chef Pierre Colander; Cost: 1.27 2
以下代码演示了读取产品名称和价格的操作(价格简单地读作一个float),跳过“Product:”和“Cost:”子串,以及分号。注意,因为scanner默认忽略空白字符和换行符,循环中没有指定对它们的处理(尤其对于读取末尾的整数而言,并不需要处理额外的空白字符)。


NSString *string = @"Product: Acme Potato Peeler; Cost: 0.98 73\n\
                     Product: Chef Pierre Pasta Fork; Cost: 0.75 19\n\
                     Product: Chef Pierre Colander; Cost: 1.27 2\n";
NSCharacterSet *semicolonSet;
NSScanner *theScanner;

NSString *PRODUCT = @"Product:";
NSString *COST = @"Cost:";

NSString *productName;
float productCost;
NSInteger productSold;

semicolonSet = [NSCharacterSet characterSetWithCharactersInString:@";"];
theScanner = [NSScanner scannerWithString:string];

while (![theScanner isAtEnd])  
{
    if ([theScanner scanString:PRODUCT intoString:NULL] &&   //从哪里开始扫描

        [theScanner scanUpToCharactersFromSet:semicolonSet   //扫描到哪里结束

                                   intoString:&productName] && //存入哪个容器

        [theScanner scanString:@";" intoString:NULL] &&

        [theScanner scanString:COST intoString:NULL] &&

        [theScanner scanFloat:&productCost] &&

        [theScanner scanInteger:&productSold])  

    {
        NSLog(@"Sales of %@: $%1.2f", productName, productCost * productSold);
    }
}

//控制台输出 Sales of Acme Potato Peeler: $71.54
           Sales of Chef Pierre Pasta Fork: $14.25
           Sales of Chef Pierre Colander: $2.54
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值