在Swift中使用Unicode代码点

如果您对蒙古语的细节不感兴趣,而只是想快速了解在Swift中使用和转换Unicode值,那么请跳至已接受答案的第一部分。


背景

我要为iOS应用程序中使用的传统蒙古语呈现Unicode文本。更好的长期解决方案是使用AAT智能字体来呈现此复杂脚本。(确实存在这样的字体,但是它们的许可证不允许修改和非个人使用。)但是,由于我从未制作过字体,更不用说AAT字体的所有渲染逻辑了,我只打算自己进行渲染。斯威夫特暂时。也许以后我可以学习制作智能字体。


在外部,我将使用Unicode文本,但在内部(以显示为UITextView),我将Unicode转换为以哑字体(用Unicode PUA值编码)存储的单个字形。因此,我的渲染引擎需要将蒙古Unicode值(范围:U + 1820到U + 1842)转换为存储在PUA中的字形值(范围:U + E360到U + E5CF)。无论如何,这是我的计划,因为这是我过去在Java中所做的,但是也许我需要改变整体思维方式。


下图显示了使用两种不同形式的字母u(用红色)在蒙古语中写过su两次。(蒙古语是垂直书写的,字母像草书字母一样用英语连接。)


在此处输入图片说明


在Unicode中,这两个字符串将表示为


var suForm1: String = "\u{1830}\u{1826}"

var suForm2: String = "\u{1830}\u{1826}\u{180B}"

suForm2Swift 将自由变体选择器(U + 180B)识别(正确)为在其前面String带有u(U + 1826)的单元。Swift将其视为单个字符,扩展的字素簇。但是,出于自己进行渲染的目的,我需要将u(U + 1826)和FVS1(U + 180B)区分为两个不同的UTF-16代码点。


为了内部显示,我将上述Unicode字符串转换为以下呈现的字形字符串:


suForm1 = "\u{E46F}\u{E3BA}" 

suForm2 = "\u{E46F}\u{E3BB}"

我一直在和Swift String和Character。关于它们有很多方便的事情,但是由于在我的特殊情况下,我只处理UTF-16代码单元,所以我想知道是否应该使用旧的NSString而不是Swift的代码String。我意识到我可以String.utf16用来获取UTF-16代码点,但是转换回String并不是很好。


坚持使用String和Character还是应该使用NSString和更好unichar?


慕斯709654
浏览 730回答 2
2回答

素胚勾勒不出你

为Swift 3更新字符串和字符对于几乎每个人都在谁访问了这个问题,未来String,并Character会为你的答案。直接在代码中设置Unicode值:var str: String = "I want to visit 北京, Москва, मुंबई, القاهرة, and 서울시. ?"var character: Character = "?"使用十六进制设置值var str: String = "\u{61}\u{5927}\u{1F34E}\u{3C0}" // a大?πvar character: Character = "\u{65}\u{301}" // é = "e" + accent mark请注意,Swift字符可以由多个Unicode代码点组成,但看起来像是一个字符。这称为扩展字素簇。另请参阅此问题。转换为Unicode值:str.utf8str.utf16str.unicodeScalars // UTF-32String(character).utf8String(character).utf16String(character).unicodeScalars从Unicode十六进制值转换:let hexValue: UInt32 = 0x1F34E// convert hex value to UnicodeScalarguard let scalarValue = UnicodeScalar(hexValue) else {&nbsp; &nbsp; // early exit if hex does not form a valid unicode value&nbsp; &nbsp; return}// convert UnicodeScalar to Stringlet myString = String(scalarValue) // ?或者:let hexValue: UInt32 = 0x1F34Eif let scalarValue = UnicodeScalar(hexValue) {&nbsp; &nbsp; let myString = String(scalarValue)}其他一些例子let value0: UInt8 = 0x61let value1: UInt16 = 0x5927let value2: UInt32 = 0x1F34Elet string0 = String(UnicodeScalar(value0)) // alet string1 = String(UnicodeScalar(value1)) // 大let string2 = String(UnicodeScalar(value2)) // ?// convert hex array to Stringlet myHexArray = [0x43, 0x61, 0x74, 0x203C, 0x1F431] // an Int arrayvar myString = ""for hexValue in myHexArray {&nbsp; &nbsp; myString.append(UnicodeScalar(hexValue))}print(myString) // Cat‼?请注意,对于UTF-8和UTF-16,转换并不总是那么容易。(请参阅UTF-8,UTF-16和UTF-32问题。)NSString和unichar也可能与工作NSString和unichar斯威夫特,但你应该明白,除非你是熟悉的语法转换为斯威夫特目标C和好,这将是很难找到良好的文档。同样,unichar是一个UInt16数组,如上所述,从UInt16Unicode标量值的转换并不总是那么容易(即,将诸如emoji表情和其他字符的对象的替代对在上层代码平面中转换)。自定义字符串结构由于问题中提到的原因,我最终没有使用任何上述方法。相反,我编写了自己的字符串结构,该结构基本上是一个数组,UInt32用于保存Unicode标量值。同样,这不是大多数人的解决方案。如果只需要扩展或扩展一点功能,请首先考虑使用扩展。StringCharacter但是,如果确实需要专门处理Unicode标量值,则可以编写自定义结构。优点是:不需要类型(间不断切换String,Character,UnicodeScalar,UInt32做字符串操作时,等)。完成Unicode操作后,最终的转换String很容易。易于在需要时添加更多方法简化了从Java或其他语言的代码转换缺点是:使代码的可移植性和其他Swift开发人员的可读性降低没有像本机Swift类型那样经过充分测试和优化它是您每次需要时都必须包含在项目中的另一个文件您可以自己制作,但这是我的参考。最难的部分是使其变得可哈希化。// This struct is an array of UInt32 to hold Unicode scalar values// Version 3.4.0 (Swift 3 update)struct ScalarString: Sequence, Hashable, CustomStringConvertible {&nbsp; &nbsp; fileprivate var scalarArray: [UInt32] = []&nbsp; &nbsp; init() {&nbsp; &nbsp; &nbsp; &nbsp; // does anything need to go here?&nbsp; &nbsp; }&nbsp; &nbsp; init(_ character: UInt32) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(character)&nbsp; &nbsp; }&nbsp; &nbsp; init(_ charArray: [UInt32]) {&nbsp; &nbsp; &nbsp; &nbsp; for c in charArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(c)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; init(_ string: String) {&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Generator in order to conform to SequenceType protocol&nbsp; &nbsp; // (to allow users to iterate as in `for myScalarValue in myScalarString` { ... })&nbsp; &nbsp; func makeIterator() -> AnyIterator<UInt32> {&nbsp; &nbsp; &nbsp; &nbsp; return AnyIterator(scalarArray.makeIterator())&nbsp; &nbsp; }&nbsp; &nbsp; // append&nbsp; &nbsp; mutating func append(_ scalar: UInt32) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; mutating func append(_ scalarString: ScalarString) {&nbsp; &nbsp; &nbsp; &nbsp; for scalar in scalarString {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; mutating func append(_ string: String) {&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // charAt&nbsp; &nbsp; func charAt(_ index: Int) -> UInt32 {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray[index]&nbsp; &nbsp; }&nbsp; &nbsp; // clear&nbsp; &nbsp; mutating func clear() {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.removeAll(keepingCapacity: true)&nbsp; &nbsp; }&nbsp; &nbsp; // contains&nbsp; &nbsp; func contains(_ character: UInt32) -> Bool {&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; }&nbsp; &nbsp; // description (to implement Printable protocol)&nbsp; &nbsp; var description: String {&nbsp; &nbsp; &nbsp; &nbsp; return self.toString()&nbsp; &nbsp; }&nbsp; &nbsp; // endsWith&nbsp; &nbsp; func endsWith() -> UInt32? {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.last&nbsp; &nbsp; }&nbsp; &nbsp; // indexOf&nbsp; &nbsp; // returns first index of scalar string match&nbsp; &nbsp; func indexOf(_ string: ScalarString) -> Int? {&nbsp; &nbsp; &nbsp; &nbsp; if scalarArray.count < string.length {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; for i in 0...(scalarArray.count - string.length) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for j in 0..<string.length {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if string.charAt(j) != scalarArray[i + j] {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break // substring mismatch&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if j == string.length - 1 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; }&nbsp; &nbsp; // insert&nbsp; &nbsp; mutating func insert(_ scalar: UInt32, atIndex index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.insert(scalar, at: index)&nbsp; &nbsp; }&nbsp; &nbsp; mutating func insert(_ string: ScalarString, atIndex index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; var newIndex = index&nbsp; &nbsp; &nbsp; &nbsp; for scalar in string {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.insert(scalar, at: newIndex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newIndex += 1&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; mutating func insert(_ string: String, atIndex index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; var newIndex = index&nbsp; &nbsp; &nbsp; &nbsp; for scalar in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.insert(scalar.value, at: newIndex)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newIndex += 1&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // isEmpty&nbsp; &nbsp; var isEmpty: Bool {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.count == 0&nbsp; &nbsp; }&nbsp; &nbsp; // hashValue (to implement Hashable protocol)&nbsp; &nbsp; var hashValue: Int {&nbsp; &nbsp; &nbsp; &nbsp; // DJB Hash Function&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.reduce(5381) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ($0 << 5) &+ $0 &+ Int($1)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // length&nbsp; &nbsp; var length: Int {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.count&nbsp; &nbsp; }&nbsp; &nbsp; // remove character&nbsp; &nbsp; mutating func removeCharAt(_ index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.remove(at: index)&nbsp; &nbsp; }&nbsp; &nbsp; func removingAllInstancesOfChar(_ character: UInt32) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar != character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; func removeRange(_ range: CountableRange<Int>) -> ScalarString? {&nbsp; &nbsp; &nbsp; &nbsp; if range.lowerBound < 0 || range.upperBound > scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in 0..<scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if i < range.lowerBound || i >= range.upperBound {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; // replace&nbsp; &nbsp; func replace(_ character: UInt32, withChar replacementChar: UInt32) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(replacementChar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; func replace(_ character: UInt32, withString replacementString: String) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(replacementString)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; func replaceRange(_ range: CountableRange<Int>, withString replacementString: ScalarString) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in 0..<scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if i < range.lowerBound || i >= range.upperBound {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if i == range.lowerBound {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(replacementString)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; // set (an alternative to myScalarString = "some string")&nbsp; &nbsp; mutating func set(_ string: String) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.removeAll(keepingCapacity: false)&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // split&nbsp; &nbsp; func split(atChar splitChar: UInt32) -> [ScalarString] {&nbsp; &nbsp; &nbsp; &nbsp; var partsArray: [ScalarString] = []&nbsp; &nbsp; &nbsp; &nbsp; if self.scalarArray.count == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return partsArray&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var part: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == splitChar {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; partsArray.append(part)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; part = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; part.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; partsArray.append(part)&nbsp; &nbsp; &nbsp; &nbsp; return partsArray&nbsp; &nbsp; }&nbsp; &nbsp; // startsWith&nbsp; &nbsp; func startsWith() -> UInt32? {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.first&nbsp; &nbsp; }&nbsp; &nbsp; // substring&nbsp; &nbsp; func substring(_ startIndex: Int) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; // from startIndex to end of string&nbsp; &nbsp; &nbsp; &nbsp; var subArray: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in startIndex..<self.length {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subArray.append(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return subArray&nbsp; &nbsp; }&nbsp; &nbsp; func substring(_ startIndex: Int, _ endIndex: Int) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; // (startIndex is inclusive, endIndex is exclusive)&nbsp; &nbsp; &nbsp; &nbsp; var subArray: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in startIndex..<endIndex {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subArray.append(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return subArray&nbsp; &nbsp; }&nbsp; &nbsp; // toString&nbsp; &nbsp; func toString() -> String {&nbsp; &nbsp; &nbsp; &nbsp; var string: String = ""&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if let validScalor = UnicodeScalar(scalar) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string.append(Character(validScalor))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return string&nbsp; &nbsp; }&nbsp; &nbsp; // trim&nbsp; &nbsp; // removes leading and trailing whitespace (space, tab, newline)&nbsp; &nbsp; func trim() -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; //var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; let space: UInt32 = 0x00000020&nbsp; &nbsp; &nbsp; &nbsp; let tab: UInt32 = 0x00000009&nbsp; &nbsp; &nbsp; &nbsp; let newline: UInt32 = 0x0000000A&nbsp; &nbsp; &nbsp; &nbsp; var startIndex = self.scalarArray.count&nbsp; &nbsp; &nbsp; &nbsp; var endIndex = 0&nbsp; &nbsp; &nbsp; &nbsp; // leading whitespace&nbsp; &nbsp; &nbsp; &nbsp; for i in 0..<self.scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if self.scalarArray[i] != space &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray[i] != tab &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray[i] != newline {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; startIndex = i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // trailing whitespace&nbsp; &nbsp; &nbsp; &nbsp; for i in stride(from: (self.scalarArray.count - 1), through: 0, by: -1) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if self.scalarArray[i] != space &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray[i] != tab &&&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray[i] != newline {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endIndex = i + 1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if endIndex <= startIndex {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return self.substring(startIndex, endIndex)&nbsp; &nbsp; }&nbsp; &nbsp; // values&nbsp; &nbsp; func values() -> [UInt32] {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray&nbsp; &nbsp; }}func ==(left: ScalarString, right: ScalarString) -> Bool {&nbsp; &nbsp; return left.scalarArray == right.scalarArray}func +(left: ScalarString, right: ScalarString) -> ScalarString {&nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; for scalar in left.values() {&nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; for scalar in right.values() {&nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; return returnString}

HUWWW

//Swift 3.0&nbsp;&nbsp;// This struct is an array of UInt32 to hold Unicode scalar valuesstruct ScalarString: Sequence, Hashable, CustomStringConvertible {&nbsp; &nbsp; private var scalarArray: [UInt32] = []&nbsp; &nbsp; init() {&nbsp; &nbsp; &nbsp; &nbsp; // does anything need to go here?&nbsp; &nbsp; }&nbsp; &nbsp; init(_ character: UInt32) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(character)&nbsp; &nbsp; }&nbsp; &nbsp; init(_ charArray: [UInt32]) {&nbsp; &nbsp; &nbsp; &nbsp; for c in charArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(c)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; init(_ string: String) {&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // Generator in order to conform to SequenceType protocol&nbsp; &nbsp; // (to allow users to iterate as in `for myScalarValue in myScalarString` { ... })&nbsp; &nbsp; //func generate() -> AnyIterator<UInt32> {&nbsp; &nbsp; func makeIterator() -> AnyIterator<UInt32> {&nbsp; &nbsp; &nbsp; &nbsp; let nextIndex = 0&nbsp; &nbsp; &nbsp; &nbsp; return AnyIterator {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (nextIndex > self.scalarArray.count-1) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray[nextIndex + 1]&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // append&nbsp; &nbsp; mutating func append(scalar: UInt32) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; mutating func append(scalarString: ScalarString) {&nbsp; &nbsp; &nbsp; &nbsp; for scalar in scalarString {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; mutating func append(string: String) {&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // charAt&nbsp; &nbsp; func charAt(index: Int) -> UInt32 {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray[index]&nbsp; &nbsp; }&nbsp; &nbsp; // clear&nbsp; &nbsp; mutating func clear() {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.removeAll(keepingCapacity: true)&nbsp; &nbsp; }&nbsp; &nbsp; // contains&nbsp; &nbsp; func contains(character: UInt32) -> Bool {&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; }&nbsp; &nbsp; // description (to implement Printable protocol)&nbsp; &nbsp; var description: String {&nbsp; &nbsp; &nbsp; &nbsp; var string: String = ""&nbsp; &nbsp; &nbsp; &nbsp; for scalar in scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string.append(String(describing: UnicodeScalar(scalar))) //.append(UnicodeScalar(scalar)!)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return string&nbsp; &nbsp; }&nbsp; &nbsp; // endsWith&nbsp; &nbsp; func endsWith() -> UInt32? {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.last&nbsp; &nbsp; }&nbsp; &nbsp; // insert&nbsp; &nbsp; mutating func insert(scalar: UInt32, atIndex index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.insert(scalar, at: index)&nbsp; &nbsp; }&nbsp; &nbsp; // isEmpty&nbsp; &nbsp; var isEmpty: Bool {&nbsp; &nbsp; &nbsp; &nbsp; get {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.count == 0&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // hashValue (to implement Hashable protocol)&nbsp; &nbsp; var hashValue: Int {&nbsp; &nbsp; &nbsp; &nbsp; get {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // DJB Hash Function&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var hash = 5381&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i in 0 ..< scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hash = ((hash << 5) &+ hash) &+ Int(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /*&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for i in 0..< self.scalarArray.count {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hash = ((hash << 5) &+ hash) &+ Int(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;*/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return hash&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // length&nbsp; &nbsp; var length: Int {&nbsp; &nbsp; &nbsp; &nbsp; get {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.count&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // remove character&nbsp; &nbsp; mutating func removeCharAt(index: Int) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.remove(at: index)&nbsp; &nbsp; }&nbsp; &nbsp; func removingAllInstancesOfChar(character: UInt32) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar != character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; // replace&nbsp; &nbsp; func replace(character: UInt32, withChar replacementChar: UInt32) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: replacementChar) //.append(replacementChar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; // func replace(character: UInt32, withString replacementString: String) -> ScalarString {&nbsp; &nbsp; func replace(character: UInt32, withString replacementString: ScalarString) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == character {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalarString: replacementString) //.append(replacementString)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return returnString&nbsp; &nbsp; }&nbsp; &nbsp; // set (an alternative to myScalarString = "some string")&nbsp; &nbsp; mutating func set(string: String) {&nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.removeAll(keepingCapacity: false)&nbsp; &nbsp; &nbsp; &nbsp; for s in string.unicodeScalars {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.scalarArray.append(s.value)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; // split&nbsp; &nbsp; func split(atChar splitChar: UInt32) -> [ScalarString] {&nbsp; &nbsp; &nbsp; &nbsp; var partsArray: [ScalarString] = []&nbsp; &nbsp; &nbsp; &nbsp; var part: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if scalar == splitChar {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; partsArray.append(part)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; part = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; part.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; partsArray.append(part)&nbsp; &nbsp; &nbsp; &nbsp; return partsArray&nbsp; &nbsp; }&nbsp; &nbsp; // startsWith&nbsp; &nbsp; func startsWith() -> UInt32? {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray.first&nbsp; &nbsp; }&nbsp; &nbsp; // substring&nbsp; &nbsp; func substring(startIndex: Int) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; // from startIndex to end of string&nbsp; &nbsp; &nbsp; &nbsp; var subArray: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in startIndex ..< self.length {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subArray.append(scalar: self.scalarArray[i]) //.append(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return subArray&nbsp; &nbsp; }&nbsp; &nbsp; func substring(startIndex: Int, _ endIndex: Int) -> ScalarString {&nbsp; &nbsp; &nbsp; &nbsp; // (startIndex is inclusive, endIndex is exclusive)&nbsp; &nbsp; &nbsp; &nbsp; var subArray: ScalarString = ScalarString()&nbsp; &nbsp; &nbsp; &nbsp; for i in startIndex ..< endIndex {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subArray.append(scalar: self.scalarArray[i]) //.append(self.scalarArray[i])&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return subArray&nbsp; &nbsp; }&nbsp; &nbsp; // toString&nbsp; &nbsp; func toString() -> String {&nbsp; &nbsp; &nbsp; &nbsp; let string: String = ""&nbsp; &nbsp; &nbsp; &nbsp; for scalar in self.scalarArray {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; string.appending(String(describing:UnicodeScalar(scalar))) //.append(UnicodeScalar(scalar)!)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return string&nbsp; &nbsp; }&nbsp; &nbsp; // values&nbsp; &nbsp; func values() -> [UInt32] {&nbsp; &nbsp; &nbsp; &nbsp; return self.scalarArray&nbsp; &nbsp; }}func ==(left: ScalarString, right: ScalarString) -> Bool {&nbsp; &nbsp; if left.length != right.length {&nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; }&nbsp; &nbsp; for i in 0 ..< left.length {&nbsp; &nbsp; &nbsp; &nbsp; if left.charAt(index: i) != right.charAt(index: i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return true}func +(left: ScalarString, right: ScalarString) -> ScalarString {&nbsp; &nbsp; var returnString = ScalarString()&nbsp; &nbsp; for scalar in left.values() {&nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; for scalar in right.values() {&nbsp; &nbsp; &nbsp; &nbsp; returnString.append(scalar: scalar) //.append(scalar)&nbsp; &nbsp; }&nbsp; &nbsp; return returnString}
打开App,查看更多内容
随时随地看视频慕课网APP