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

时间:2014-09-29 17:11:40

标签: swift character literals

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...}

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

5 个答案:

答案 0 :(得分:11)

只要Character只由一个字符组成,就可以从String创建

String。而且,由于Character实现ExtendedGraphemeClusterLiteralConvertible,Swift会在分配时自动为您执行此操作。因此,要在Swift中创建Character,您可以执行以下操作:

let ch: Character = "a"

然后,您可以使用contains的{​​{1}}方法(使用Range operators生成)来检查字符是否在您要查找的范围内:

IntervalType

示例:

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

输出:

  

是的


更新:正如@MartinR指出的那样,Swift字符的排序基于Unicode Normalization Form D的顺序与ASCII字符代码的顺序相同。在您的特定情况下,let ch: Character = "m" if ("a"..."z").contains(ch) { println("yep") } else { println("nope") } a之间的字符数比直接ASCII(例如z)多。有关详细信息,请参阅@ MartinR的答案here

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

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

注意:这两个示例只有在角色只包含一个代码点时才有效,但是,只要我们仅限于ASCII,这应该不是问题

答案 1 :(得分: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 )

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

答案 2 :(得分:2)

您想要的功能可能会出现在Swift 5.1中!您可以在SE-0243: Integer-convertible character literals中了解它。

语法可能看起来像这样:

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

答案 3 :(得分:0)

您似乎还可以使用以下语法:

Character("a")

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

我仅在Swift 4和Xcode 10.1中对此进行了测试

答案 4 :(得分:0)

为什么我要挖掘7岁的帖子?好玩吗?认真地说,我想我可以加入讨论。

这不是一个漏洞,而是一个故意阻止将文本字符串与ASCII字节序列混合的故意漏洞。

您绝对可以挑选一个字符串。字符串实现BidirectionalCollection并具有许多操作原子的方法。请参阅:https://developer.apple.com/documentation/swift/string。 但是您必须习惯于更广义的字符串概念。可以从 User 透视图(它是一系列字素簇,通常在视觉上可分离的外观)中选择,也可以从 encoding 透视图中选择。是以下几种之一(UTF32,UTF16,UTF8)。

可能会过度分析您的问题的措辞:

  • 数据结构是概念性的,与存储中的编码无关
  • 编码为ASCII字符串的数据结构只是一种ASCII字符串
  • 通过设计,ASCII值0-127的编码在UTF-8中将具有相同的编码,因此可以使用UTF8 API加载该流
  • 编码为字符串的数据结构(其中结构的字段具有UTF-8 Unicode字符串值)不是ASCII字符串,而是UTF-8字符串本身
  • 字符串是否经过ASCII编码; “出于实际目的”不是有意义的限定词。一个UTF-8数据库字段,其中99.99%的文本都落在ASCII范围内(在其中编码会匹配),但有时不匹配,这会带来一些令人讨厌的错误机会。

Swift具有更丰富的API,可以对涉及的类别和实体进行更明确的命名,而不是固定宽度的整数和仅包含英文的文本的简短而底层的等效项。如果要处理ASCII,则有一个名称(方法),如果要处理人的子类别,也有一个名称,它们彼此完全独立。与ASCII和以英语为中心的字符串处理模型C相比,它有很大的发展。这是事实,没有传福音,并且可以呈现令人讨厌的学习曲线。

(这是针对新来者的,承认OP可能已有多年的经验。)

对于您要在那里做的事情,请考虑:

let foo = "abcDeé@¶œŎO!@#"

foo.forEach { c in
    print((c.isASCII ? "\(c) is ascii with value \(c.asciiValue ?? 0); " : "\(c) is not ascii; ")
        + ((c.isLetter ? "\(c) is a letter" : "\(c) is not a letter")))
}
b is ascii with value 98; b is a letter
c is ascii with value 99; c is a letter
D is ascii with value 68; D is a letter
e is ascii with value 101; e is a letter
é is not ascii; é is a letter
@ is ascii with value 64; @ is not a letter
¶ is not ascii; ¶ is not a letter
œ is not ascii; œ is a letter
Ŏ is not ascii; Ŏ is a letter
O is ascii with value 79; O is a letter
! is ascii with value 33; ! is not a letter
@ is ascii with value 64; @ is not a letter
# is ascii with value 35; # is not a letter
相关问题