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

问题描述 投票:13回答:4

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

String foo="a"
char bar='a'

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

let ch:unichar = arrayOfCharacters[n]
if ch >= 'a' && ch <= 'z' {...whatever...}

一个相当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...}

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

swift character literals
4个回答
12
投票

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

let ch: Character = "a"

然后,您可以使用containsIntervalType方法(使用Range operators生成)来检查角色是否在您正在寻找的范围内:

if ("a"..."z").contains(ch) {
    /* ... whatever ... */
}

例:

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

输出:

是的


更新:正如@MartinR指出的那样,Swift字符的排序基于Unicode Normalization Form D,它与ASCII字符代码的顺序不同。在您的特定情况下,az之间的字符数比直接ASCII(例如ä)更多。有关详细信息,请参阅@ MartinR的答案here

如果您需要检查字符是否在两个ASCII字符代码之间,那么您可能需要执行类似于原始解决方法的操作。但是,您还需要将ch转换为unichar而不是Character才能使其工作(有关this questionCharacter的更多信息,请参阅unichar):

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")
}

或者,没有使用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")
}

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


7
投票

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

let chr = UInt8(ascii:"A") // == UInt8( 0x41 )

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

let unichr1 = UnicodeScalar("A").value // == UInt32( 0x41 )
let unichr2 = UnicodeScalar("é").value // == UInt32( 0xe9 )
let unichr3 = UnicodeScalar("😀").value // == UInt32( 0x1f600 )

或者16位:

let unichr1 = UInt16(UnicodeScalar("A").value) // == UInt16( 0x41 )
let unichr2 = UInt16(UnicodeScalar("é").value) // == UInt16( 0xe9 )

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


4
投票

你想要的功能是proposed to be in Swift 5.1,但该提议被拒绝的原因有以下几点:

  1. 歧义 在当前的Swift生态系统中写的提议将允许像'x' + 'y' == "xy"这样的表达式,这不是有意的(正确的语法将是"x" + "y" == "xy")。
  2. 合并 该提案是二合一的。 首先,它提出了一种将单引号文字引入语言的方法。 其次,它提出这些可以转换为数字类型来处理ASCII值和Unicode代码点。 这些都是很好的建议,建议将其拆分为两个并重新提出。这些后续提案尚未正式确定。
  3. 异议 无论'x'的默认类型是Character还是Unicode.Scalar,它都没有达成共识。尽管缺乏共识,但Character引用了Principle of Least Surprise的提议。

你可以阅读the full rejection rationale here


语法可能/看起来像这样:

let myChar = 'f' // Type is Character, value is solely the unicode U+0066 LATIN SMALL LETTER F
let myInt8: Int8 = 'f' // Type is Int8, value is 102 (0x66)
let myUInt8Array: [UInt8] = [ 'a', 'b', '1', '2' ] // Type is [UInt8], value is [ 97, 98, 49, 50 ] ([ 0x61, 0x62, 0x31, 0x32 ])

switch someUInt8 {
    case 'a' ... 'f': return "Lowercase hex letter"
    case 'A' ... 'F': return "Uppercase hex letter"
    case '0' ... '9': return "Hex digit"
    default: return "Non-hex character"
}

0
投票

看起来您也可以使用以下语法:

Character("a")

这将从指定的单个字符串创建一个Character

我只在Swift 4和Xcode 10.1中测试了这个

© www.soinside.com 2019 - 2024. All rights reserved.