来自NSCharacterset的NSArray

目前我能够制作如下的字母数组

[[NSArray alloc]initWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K",@"L",@"M",@"N",@"O",@"P",@"Q",@"R",@"S",@"T",@"U",@"V",@"W",@"X",@"Y",@"Z",nil]; 

知道可以结束

 [NSCharacterSet uppercaseLetterCharacterSet] 

无论如何,我可以做出一个数组呢?

以下代码创build一个包含给定字符集的所有字符的数组。 它也适用于“基础多语种飞机”以外的字符(字符> U + FFFF,例如U + 10400 DESERET CAPITAL LETTER LONG I)。

 NSCharacterSet *charset = [NSCharacterSet uppercaseLetterCharacterSet]; NSMutableArray *array = [NSMutableArray array]; for (int plane = 0; plane <= 16; plane++) { if ([charset hasMemberInPlane:plane]) { UTF32Char c; for (c = plane << 16; c < (plane+1) << 16; c++) { if ([charset longCharacterIsMember:c]) { UTF32Char c1 = OSSwapHostToLittleInt32(c); // To make it byte-order safe NSString *s = [[NSString alloc] initWithBytes:&c1 length:4 encoding:NSUTF32LittleEndianStringEncoding]; [array addObject:s]; } } } } 

对于uppercaseLetterCharacterSet这给出了1467个元素的数组。 但是请注意,字符> U + FFFF在NSString被存储为UTF-16代理对,所以例如U + 10400实际上被存储在NSString作为2个字符“\ uD801 \ uDC00”。

Swift 2代码可以在这个问题的其他答案中find。 这里是一个Swift 3版本,写成扩展方法:

 extension CharacterSet { func allCharacters() -> [Character] { var result: [Character] = [] for plane: UInt8 in 0...16 where self.hasMember(inPlane: plane) { for unicode in UInt32(plane) << 16 ..< UInt32(plane + 1) << 16 { if let uniChar = UnicodeScalar(unicode), self.contains(uniChar) { result.append(Character(uniChar)) } } } return result } } 

例:

 let charset = CharacterSet.uppercaseLetters let chars = charset.allCharacters() print(chars.count) // 1521 print(chars) // ["A", "B", "C", ... "] 

(请注意,用于显示结果的字体中可能不存在某些字符。)

由于字符具有有限的(有限的)范围,所以你可以testing哪些字符是给定字符集的成员(蛮力):

 // this doesn't seem to be available #define UNICHAR_MAX (1ull << (CHAR_BIT * sizeof(unichar))) NSData *data = [[NSCharacterSet uppercaseLetterCharacterSet] bitmapRepresentation]; uint8_t *ptr = [data bytes]; NSMutableArray *allCharsInSet = [NSMutableArray array]; // following from Apple's sample code for (unichar i = 0; i < UNICHAR_MAX; i++) { if (ptr[i >> 3] & (1u << (i & 7))) { [allCharsInSet addObject:[NSString stringWithCharacters:&i length:1]]; } } 

我创build了一个马丁R的algorithm的Swift(v2.1)版本:

 let charset = NSCharacterSet.URLPathAllowedCharacterSet(); for var plane : UInt8 in 0...16 { if charset.hasMemberInPlane( plane ) { var c : UTF32Char; for var c : UInt32 = UInt32( plane ) << 16; c < (UInt32(plane)+1) << 16; c++ { if charset.longCharacterIsMember(c) { var c1 = c.littleEndian // To make it byte-order safe let s = NSString(bytes: &c1, length: 4, encoding: NSUTF32LittleEndianStringEncoding); NSLog("Char: \(s)"); } } } } 

这是使用一些更快的迅速完成。

 let characters = NSCharacterSet.uppercaseLetterCharacterSet() var array = [String]() for plane: UInt8 in 0...16 where characters.hasMemberInPlane(plane) { for character: UTF32Char in UInt32(plane) << 16..<(UInt32(plane) + 1) << 16 where characters.longCharacterIsMember(character) { var endian = character.littleEndian let string = NSString(bytes: &endian, length: 4, encoding: NSUTF32LittleEndianStringEncoding) as! String array.append(string) } } print(array) 

只是拉丁字母表的AZ(没有与希腊语,或变音符号,或其他不是什么人要求的东西):

 for plane: UInt8 in 0...16 where characters.hasMemberInPlane(plane) { i = 0 for character: UTF32Char in UInt32(plane) << 16...(UInt32(plane) + 1) << 16 where characters.longCharacterIsMember(character) { var endian = character.littleEndian let string = NSString(bytes: &endian, length: 4, encoding: NSUTF32LittleEndianStringEncoding) as! String array.append(string) if(array.count == 26) { break } } if(array.count == 26) { break } } 

你不应该; 这不是字符集的目的。 NSCharacterSet是一个可能无限的字符集,可能还没有发明的代码点。 所有你想知道的是“这个字符或字符集合在这个集合吗?”,为此,它是有用的。

想象一下这个Swift代码:

 let asciiCodepoints = Unicode.Scalar(0x00)...Unicode.Scalar(0x7F) let asciiCharacterSet = CharacterSet(charactersIn: asciiCodepoints) let nonAsciiCharacterSet = asciiCharacterSet.inverted 

这与Objective-C代码类似:

 NSRange asciiCodepoints = NSMakeRange(0x00, 0x7F); NSCharacterSet * asciiCharacterSet = [NSCharacterSet characterSetWithRange:asciiCodepoints]; NSCharacterSet * nonAsciiCharacterSet = asciiCharacterSet.invertedSet; 

很容易说“循环遍历asciiCharacterSet所有字符”; 这只会遍历从U+0000U+007F所有字符。 但是,什么是循环所有nonAsciiCharacterSet的字符? 你从U+0080开始? 谁能说将来不会有负面的代码点? 你在哪里结束? 你跳过不可打印的字符? 那么扩展字形集群呢? 既然它是一个集合(顺序无关紧要),你的代码是否可以在这个循环中处理无序的代码点呢?

这些是你不想在这里回答的问题; 在function上, nonAsciiCharacterSet是无限的,所有你想要使用它是为了告诉是否有任何给定的字符在ASCII字符集之外。


你应该真正问自己的问题是: “我想用这些大写字母来完成什么? 如果(也可能只有)你真的需要按顺序迭代它,把你关心的放在一个ArrayString (可能是从资源文件读入)可能是最好的方法。 如果你想检查一个字符是否是大写字母集合的一部分,那么你不需要关心顺序或者甚至在集合中有多less个字符 ,并且应该使用CharacterSet.uppercaseLetters.contains(foo) (in Objective-C: [NSCharacterSet.uppercaseLetterCharacterSet contains: foo] )。

也想想非拉丁字符。 CharacterSet.uppercaseLetters涵盖Unicode常规类别Lu和Lt ,它们包含AZ以及诸如Dž𝕹Խ 。 你不想要这样想。 当Unicode联盟将新字符添加到此列表中时,您肯定不希望向您的应用程序发出更新。 如果你想要做的是决定是否大写,不要打扰任何东西的硬编码。