Objective c 迭代NSString中所有字符的最有效方法
迭代NSString中所有字符的最佳方法是什么?是否要在字符串长度上循环并使用该方法Objective c 迭代NSString中所有字符的最有效方法,objective-c,Objective C,迭代NSString中所有字符的最佳方法是什么?是否要在字符串长度上循环并使用该方法 [aNSString characterAtIndex:index]; 或者,您想使用基于NSString的字符缓冲区吗?我肯定会先得到一个字符缓冲区,然后在上面迭代 NSString *someString = ... unsigned int len = [someString length]; char buffer[len]; //This way: strncpy(buffer, [someSt
[aNSString characterAtIndex:index];
或者,您想使用基于NSString的字符缓冲区吗?我肯定会先得到一个字符缓冲区,然后在上面迭代
NSString *someString = ...
unsigned int len = [someString length];
char buffer[len];
//This way:
strncpy(buffer, [someString UTF8String]);
//Or this way (preferred):
[someString getCharacters:buffer range:NSMakeRange(0, len)];
for(int i = 0; i < len; ++i) {
char current = buffer[i];
//do something with current...
}
NSString*someString=。。。
无符号整数长度=[someString长度];
字符缓冲区[len];
//这样:
strncpy(缓冲区,[someString UTF8String]);
//或通过这种方式(首选):
[someString getCharacters:缓冲区范围:NSMakerRange(0,len)];
对于(int i=0;i
两者都不是。委员会建议:
如果您想在
字符串的字符,其中一个
你不应该做的事情是使用
characterAtIndex:
要检索的方法
每个字符分别显示。这种方法
不是为重复访问而设计的。
取而代之的是考虑取回
使用
getCharacters:范围:
方法和
直接迭代字节
如果要在字符串中搜索
特定字符或子字符串,是否
不遍历一个字符
一个接一个。相反,使用更高的级别
方法,例如rangeOfString:
,
rangeOfCharacterFromSet:
,或
substringWithRange:
,它们是
优化搜索NSString
人物
查看此示例,了解如何让
rangeOfCharacterFromSet:
迭代字符串中的字符,而不是自己进行迭代。我认为人们了解如何处理unicode很重要,因此我最终以tl的精神编写了一个怪物答案;dr我将从一个应该可以正常工作的片段开始。如果你想知道细节(你应该知道!),请在片段之后继续阅读
NSUInteger len = [str length];
unichar buffer[len+1];
[str getCharacters:buffer range:NSMakeRange(0, len)];
NSLog(@"getCharacters:range: with unichar buffer");
for(int i = 0; i < len; i++) {
NSLog(@"%C", buffer[i]);
}
另一方面,如果您想在字符串中的字节上迭代,那么它开始变得复杂,结果将完全取决于您选择使用的编码。不错的默认选择是UTF8,这就是我要展示的
要执行此操作,您必须计算出生成的UTF8字符串的字节数,这一步很容易出错,并使用字符串的-长度
。这很容易出错的一个主要原因,特别是对于美国开发人员来说,是一个字母落入7位ASCII频谱的字符串将具有相等的字节和字母长度。这是因为UTF8用一个字节对7位ASCII字母进行编码,所以一个简单的测试字符串和基本英文文本可能工作得很好
正确的方法是使用方法-lengthofBytes usingencoding:NSUTF8StringEncoding
(或其他编码),分配具有该长度的缓冲区,然后使用-cStringUsingEncoding:
将字符串转换为相同的编码,并将其复制到该缓冲区。此处的示例代码:
NSUInteger byteLength = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
char proper_c_buffer[byteLength+1];
strncpy(proper_c_buffer, [str cStringUsingEncoding:NSUTF8StringEncoding], byteLength);
NSLog(@"strncpy with proper length");
for(int i = 0; i < byteLength; i++) {
NSLog(@"%c", proper_c_buffer[i]);
}
虽然从技术上讲,您将获得单个NSString值,但有一种替代方法:
NSRange range = NSMakeRange(0, 1);
for (__unused int i = range.location; range.location < [starring length]; range.location++) {
NSLog(@"%@", [aNSString substringWithRange:range]);
}
NSRange range=NSMakeRange(0,1);
对于(_unused int i=range.location;range.location<[starring length];range.location++){
NSLog(@“%@,[aNSString substringWithRange:range]);
}
(未使用的int i位是使编译器警告静音所必需的。)虽然Daniel的解决方案可能大部分时间都有效,但我认为解决方案取决于上下文。例如,我有一个拼写应用程序,需要在每个字符出现在屏幕上时对其进行迭代,这可能与它在内存中的表示方式不一致。用户提供的文本尤其如此 在NSString上使用类似于此类别的内容:
- (void) dumpChars
{
NSMutableArray *chars = [NSMutableArray array];
NSUInteger len = [self length];
unichar buffer[len+1];
[self getCharacters: buffer range: NSMakeRange(0, len)];
for (int i=0; i<len; i++) {
[chars addObject: [NSString stringWithFormat: @"%C", buffer[i]]];
}
NSLog(@"%@ = %@", self, [chars componentsJoinedByString: @", "]);
}
但它也可以很容易地产生:
mañana = m, a, n, ̃, a, n, a
如果字符串是预合成的unicode格式,则生成前者;如果字符串是分解格式,则生成后者
e̊gâds = e, ̊, g, â, d, s
您可能认为可以通过使用NSString的precomposedStringWithCanonicalMapping或precomposedStringWithCompatibilityMapping的结果来避免这种情况,但这不一定是Apple在中警告的情况。例如,像e̊g–ds
(完全由我编造)这样的字符串即使在转换为预合成形式后仍会生成以下内容
e̊gâds = e, ̊, g, â, d, s
我的解决方案是使用NSString的EnumerateSubstringsRange传递NSStringEnumerationByComposedCharacterSequences作为枚举选项。将前面的示例改写为如下所示:
- (void) dumpSequences
{
NSMutableArray *chars = [NSMutableArray array];
[self enumerateSubstringsInRange: NSMakeRange(0, [self length]) options: NSStringEnumerationByComposedCharacterSequences
usingBlock: ^(NSString *inSubstring, NSRange inSubstringRange, NSRange inEnclosingRange, BOOL *outStop) {
[chars addObject: inSubstring];
}];
NSLog(@"%@ = %@", self, [chars componentsJoinedByString: @", "]);
}
如果我们输入这个版本e̊g–ds
,那么我们得到
e̊gâds = e̊, g, â, d, s
正如所料,这正是我想要的
关于的文档部分也可能有助于解释其中的一些内容
注意:看起来我使用的一些unicode字符串在格式化为代码时会出错。我使用的字符串是mañana和e̊g–ds 尝试使用块枚举字符串 创建NSString的类别 h m 你不应该使用
NSUInteger len = [str length];
unichar buffer[len+1];
您应该使用内存分配
NSUInteger len = [str length];
unichar* buffer = (unichar*) malloc (len+1)*sizeof(unichar);
而最终的用途呢
free(buffer);
为了避免内存问题。对于这个问题,这是一个不同的解决方案,但我认为这可能对某些人有用。我想要的是在NSString中作为实际的unicode字符进行迭代。因此,我找到了这个解决方案:
NSString*str=@“您好,这是一个不错的方法,但值得记住的是,沿着这些行对NSString进行的任何字符转换都会遇到一些非常棘手的多字节文本边缘情况,最好尽可能避免。(不幸的是,仅仅使用UTF-16或UTF-32还不足以解决所有国际文本的问题,尽管它会将您的内存需求推向月球。)你为什么要使用字符缓冲区呢?那么Chuck,还有什么选择呢?你是说使用characterAtIndex,尽管它很昂贵吗?这根本不是正确的方法,因为unicode字符的存储方式。检查@som
@interface NSString (Category)
- (void)enumerateCharactersUsingBlock:(void (^)(NSString *character, NSInteger idx, bool *stop))block;
@end
@implementation NSString (Category)
- (void)enumerateCharactersUsingBlock:(void (^)(NSString *character, NSInteger idx, bool *stop))block
{
bool _stop = NO;
for(NSInteger i = 0; i < [self length] && !_stop; i++)
{
NSString *character = [self substringWithRange:NSMakeRange(i, 1)];
block(character, i, &_stop);
}
}
@end
NSString *string = @"Hello World";
[string enumerateCharactersUsingBlock:^(NSString *character, NSInteger idx, bool *stop) {
NSLog(@"char %@, i: %li",character, (long)idx);
}];
NSUInteger len = [str length];
unichar buffer[len+1];
NSUInteger len = [str length];
unichar* buffer = (unichar*) malloc (len+1)*sizeof(unichar);
free(buffer);