是否有一种干净的方式来指定Swift中的字符文字?

Ale*_*ark 16 character literals swift

Swift似乎试图贬低由一系列原子字符组成的字符串的概念,这对许多用途都有意义,但是有很多编程需要通过选择ASCII数据结构来实现所有实际目的:特别是文件I/O. 缺少用于指定字符文字的内置语言功能似乎是一个巨大的漏洞,即没有C/Java/etc-esque的模拟:

String foo="a"
char bar='a'
Run Code Online (Sandbox Code Playgroud)

这很不方便,因为即使将字符串转换为字符数组,也不能执行以下操作:

let ch:unichar = arrayOfCharacters[n]
if ch >= 'a' && ch <= 'z' {...whatever...}
Run Code Online (Sandbox Code Playgroud)

一个相当hacky的解决方法是做这样的事情:

let LOWCASE_A = ("a" as NSString).characterAtIndex(0)
let LOWCASE_Z = ("z" as NSString).characterAtIndex(0)
if ch >= LOWCASE_A && ch <= LOWCASE_Z {...whatever...}
Run Code Online (Sandbox Code Playgroud)

这很有效,但显然很难看.有没有人有更好的方法?

Mik*_*e S 12

Characters可以从Strings 创建,只要String它们只由一个字符组成即可.而且,由于Character实现ExtendedGraphemeClusterLiteralConvertible,Swift将在分配时自动为您执行此操作.因此,要Character在Swift中创建一个,您可以简单地执行以下操作:

let ch: Character = "a"
Run Code Online (Sandbox Code Playgroud)

然后,你可以使用contains的方法IntervalType(与生成的Range运营商),以检查是否字符是你正在寻找的范围内:

if ("a"..."z").contains(ch) {
    /* ... whatever ... */
}
Run Code Online (Sandbox Code Playgroud)

例:

let ch: Character = "m"
if ("a"..."z").contains(ch) {
    println("yep")
} else {
    println("nope")
}
Run Code Online (Sandbox Code Playgroud)

输出:

是的


更新:由于@MartinR指出,斯威夫特字符排序基于Unicode范式d这是以相同的顺序为ASCII字符代码.在您的特定情况下,在ASCII 之间a和之间存在更多字符z(ä例如).见@ MartinR的答案在这里获得更多信息.

如果您需要检查字符是否在两个ASCII字符代码之间,那么您可能需要执行类似于原始解决方法的操作.但是,您还必须转换ch为a unichar而不是Character它才能工作(有关vs的更多信息,请参阅此问题):Characterunichar

let a_code = ("a" as NSString).characterAtIndex(0)
let z_code = ("z" as NSString).characterAtIndex(0)
let ch_code = (String(ch) as NSString).characterAtIndex(0)

if (a_code...z_code).contains(ch_code) {
    println("yep")
} else {
    println("nope")
}
Run Code Online (Sandbox Code Playgroud)

或者,没有使用更加冗长的方式NSString:

let startCharScalars = "a".unicodeScalars
let startCode = startCharScalars[startCharScalars.startIndex]

let endCharScalars = "z".unicodeScalars
let endCode = endCharScalars[endCharScalars.startIndex]

let chScalars = String(ch).unicodeScalars
let chCode = chScalars[chScalars.startIndex]

if (startCode...endCode).contains(chCode) {
    println("yep")
} else {
    println("nope")
}
Run Code Online (Sandbox Code Playgroud)

注意:这两个示例仅在字符仅包含单个代码点时才起作用,但是,只要我们仅限于ASCII,这应该不是问题.


sup*_*sup 7

如果您需要C风格的ASCII文字,您可以这样做:

let chr = UInt8(ascii:"A") // == UInt8( 0x41 )
Run Code Online (Sandbox Code Playgroud)

或者,如果您需要32位Unicode文字,您可以这样做:

let unichr1 = UnicodeScalar("A").value // == UInt32( 0x41 )
let unichr2 = UnicodeScalar("é").value // == UInt32( 0xe9 )
let unichr3 = UnicodeScalar("").value // == UInt32( 0x1f600 )
Run Code Online (Sandbox Code Playgroud)

或者16位:

let unichr1 = UInt16(UnicodeScalar("A").value) // == UInt16( 0x41 )
let unichr2 = UInt16(UnicodeScalar("é").value) // == UInt16( 0xe9 )
Run Code Online (Sandbox Code Playgroud)

所有这些初始化程序都将在编译时进行评估,因此它实际上是在汇编指令级使用立即文字.