- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
遍历 NSString 中所有字符的最佳方法是什么?是否要循环遍历字符串的长度并使用该方法。
[aNSString characterAtIndex:index];
或者您想使用基于 NSString 的字符缓冲区?
最佳答案
我认为人们了解如何处理 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]);
}
还和我在一起吗?好!
当前接受的答案似乎将字节与字符/字母混淆。这是遇到 unicode 时的常见问题,尤其是来自 C 背景的情况。 Objective-C 中的字符串表示为 unicode 字符 (unichar
),它比字节大得多,不应该与标准 C 字符串操作函数一起使用。
(编辑:这还不是全部内容!令我感到非常遗憾的是,我完全忘记了考虑可组合字符,其中一个“字母”由多个 unicode 组成代码点。这为您提供了一种情况,您可以将一个“字母”解析为多个 unichars,而每个 unichars 又是多个字节。哎呀。有关详细信息,请参阅 this great answer。)
问题的正确答案取决于您是要遍历 characters/letters(不同于类型 char
)还是 bytes 字符串(类型 char
的实际含义)。本着避免混淆的精神,从现在开始,我将使用术语 byte 和 letter,避免使用可能有歧义的术语 character。
如果你想做前者并遍历字符串中的字母,你需要专门处理 unichars(对不起,但我们现在在未来,你不能再忽略它了)。查找字母的数量很容易,这是字符串的长度属性。一个示例片段是这样的(与上面相同):
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 字符串有多少字节,这是一个容易出错的步骤并使用字符串的 -length
。这很容易出错的一个主要原因,尤其是对于美国开发人员而言,是具有 7 位 ASCII 范围内的字母的字符串将具有相等的字节和字母长度。这是因为 UTF8 用一个字节编码 7 位 ASCII 字母,所以一个简单的测试字符串和基本的英文文本可能工作得很好。
正确的方法是使用 -lengthOfBytesUsingEncoding: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]);
}
为了让大家明白为什么保持直截了当很重要,我将展示以四种不同方式处理此迭代的示例代码,其中两种是错误的,两种是正确的。这是代码:
#import <Foundation/Foundation.h>
int main() {
NSString *str = @"буква";
NSUInteger len = [str length];
// Try to store unicode letters in a char array. This will fail horribly
// because getCharacters:range: takes a unichar array and will probably
// overflow or do other terrible things. (the compiler will warn you here,
// but warnings get ignored)
char c_buffer[len+1];
[str getCharacters:c_buffer range:NSMakeRange(0, len)];
NSLog(@"getCharacters:range: with char buffer");
for(int i = 0; i < len; i++) {
NSLog(@"Byte %d: %c", i, c_buffer[i]);
}
// Copy the UTF string into a char array, but use the amount of letters
// as the buffer size, which will truncate many non-ASCII strings.
strncpy(c_buffer, [str UTF8String], len);
NSLog(@"strncpy with UTF8String");
for(int i = 0; i < len; i++) {
NSLog(@"Byte %d: %c", i, c_buffer[i]);
}
// Do It Right (tm) for accessing letters by making a unichar buffer with
// the proper letter 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(@"Letter %d: %C", i, buffer[i]);
}
// Do It Right (tm) for accessing bytes, by using the proper
// encoding-handling methods
NSUInteger byteLength = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
char proper_c_buffer[byteLength+1];
const char *utf8_buffer = [str cStringUsingEncoding:NSUTF8StringEncoding];
// We copy here because the documentation tells us the string can disappear
// under us and we should copy it. Just to be safe
strncpy(proper_c_buffer, utf8_buffer, byteLength);
NSLog(@"strncpy with proper length");
for(int i = 0; i < byteLength; i++) {
NSLog(@"Byte %d: %c", i, proper_c_buffer[i]);
}
return 0;
}
运行此代码将输出以下内容(去掉 NSLog cruft),准确显示字节和字母表示的不同之处(最后两个输出):
getCharacters:range: with char buffer
Byte 0: 1
Byte 1:
Byte 2: C
Byte 3:
Byte 4: :
strncpy with UTF8String
Byte 0: Ð
Byte 1: ±
Byte 2: Ñ
Byte 3:
Byte 4: Ð
getCharacters:range: with unichar buffer
Letter 0: б
Letter 1: у
Letter 2: к
Letter 3: в
Letter 4: а
strncpy with proper length
Byte 0: Ð
Byte 1: ±
Byte 2: Ñ
Byte 3:
Byte 4: Ð
Byte 5: º
Byte 6: Ð
Byte 7: ²
Byte 8: Ð
Byte 9: °
关于objective-c - 遍历 NSString 中所有字符的最有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4158646/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!