2014-06-28 84 views

回答

1

這是一個可能的解決方案(現在更新的夫特2):

let utf8 : [CChar] = [65, 66, 67, 0] 
if let str = utf8.withUnsafeBufferPointer({ String.fromCString($0.baseAddress) }) { 
    print(str) // Output: ABC 
} else { 
    print("Not a valid UTF-8 string") 
} 

內閉合,$0UnsafeBufferPointer<CChar>指向陣列的連續的存儲。由此可以創建Swift String

或者,如果你喜歡的輸入作爲無符號字節:

let utf8 : [UInt8] = [0xE2, 0x82, 0xAC, 0] 
if let str = utf8.withUnsafeBufferPointer({ String.fromCString(UnsafePointer($0.baseAddress)) }) { 
    print(str) // Output: € 
} else { 
    print("Not a valid UTF-8 string") 
} 
+0

使用Swift語法編寫的C代碼......並且比C更醜陋(這可能是一件好事,所以人們希望避免它們) –

+1

@BryanChen:我剛纔試圖提出一個不使用Swift的解決方案基金會和Objective-C類... –

+0

我認爲真正的雨燕方法必須使用'Character'和'UTF8'某處 –

1

我會做這樣的事情,也可能是沒有這樣優雅比「指針」工作,但它的工作好,這些是相當多的關於一堆新+=運營商String,如:

@infix func += (inout lhs: String, rhs: (unit1: UInt8)) { 
    lhs += Character(UnicodeScalar(UInt32(rhs.unit1))) 
} 

@infix func += (inout lhs: String, rhs: (unit1: UInt8, unit2: UInt8)) { 
    lhs += Character(UnicodeScalar(UInt32(rhs.unit1) << 8 | UInt32(rhs.unit2))) 
} 

@infix func += (inout lhs: String, rhs: (unit1: UInt8, unit2: UInt8, unit3: UInt8, unit4: UInt8)) { 
    lhs += Character(UnicodeScalar(UInt32(rhs.unit1) << 24 | UInt32(rhs.unit2) << 16 | UInt32(rhs.unit3) << 8 | UInt32(rhs.unit4))) 
} 

注:您可以擴展與overridin支持的運營商名單g+運營商以及定義完全可交換運營商的列表String


,現在你可以到String追加使用Unicode(UTF-8,UTF-16和UTF-32)字符例如像:

var string: String = "signs of the Zodiac: " 
string += (0x0, 0x0, 0x26, 0x4b) 
string += (38) 
string += (0x26, 76) 
+0

只是一句話:你的代碼創建從UTF-32輸入一個字符串(如果我理解正確的話)和雷來自UTF-8輸入。再次讀這個問題我不是100%確定這裏要求什麼。 OP提到兩個「UTF-8」和「碼點」 ... –

+0

@MartinR,你是對的,是公平的,我不知道真正的問題提出,其原因是,就像你剛纔說的一樣。 .. – holex

+0

請注意,Unicode代碼點的UTF-8序列具有1個,2個,3個或4個字節。 –

4

改善馬丁的r答案

import AppKit 

let utf8 : CChar[] = [65, 66, 67, 0] 
let str = NSString(bytes: utf8, length: utf8.count, encoding: NSUTF8StringEncoding) 
println(str) // Output: ABC 

import AppKit 

let utf8 : UInt8[] = [0xE2, 0x82, 0xAC, 0] 
let str = NSString(bytes: utf8, length: utf8.count, encoding: NSUTF8StringEncoding) 
println(str) // Output: € 

發生了什麼事是Array可以自動轉換到CConstVoidPointer可用於與NSSString(bytes: CConstVoidPointer, length len: Int, encoding: Uint)

+3

請注意,您的代碼也會將0字節轉換爲創建的NSString中的NUL字符。 –

12

這是可能的UTF8編碼點轉換爲字符串雨燕習慣用法使用UTF8雨燕類中創建的字符串。雖然從String轉換爲UTF8更容易!

import Foundation 

public class UTF8Encoding { 
    public static func encode(bytes: Array<UInt8>) -> String { 
    var encodedString = "" 
    var decoder = UTF8() 
    var generator = bytes.generate() 
    var finished: Bool = false 
    do { 
     let decodingResult = decoder.decode(&generator) 
     switch decodingResult { 
     case .Result(let char): 
     encodedString.append(char) 
     case .EmptyInput: 
     finished = true 
     /* ignore errors and unexpected values */ 
     case .Error: 
     finished = true 
     default: 
     finished = true 
     } 
    } while (!finished) 
    return encodedString 
    } 

    public static func decode(str: String) -> Array<UInt8> { 
    var decodedBytes = Array<UInt8>() 
    for b in str.utf8 { 
     decodedBytes.append(b) 
    } 
    return decodedBytes 
    } 
} 

func testUTF8Encoding() { 
    let testString = "A UTF8 String With Special Characters: " 
    let decodedArray = UTF8Encoding.decode(testString) 
    let encodedString = UTF8Encoding.encode(decodedArray) 
    XCTAssert(encodedString == testString, "UTF8Encoding is lossless: \(encodedString) != \(testString)") 
} 

另一替代方案建議:

  • 使用NSString調用Objective-C的橋;

  • 使用UnicodeScalar容易出錯,因爲它將UnicodeScalars直接轉換爲字符,忽略複雜的字素集羣;和

  • 使用String.fromCString可能是不安全的,因爲它使用指針。

+2

感謝您解碼UTF8編碼!你可以從頂部刪除'import Foundation',這就是我想要使用它的全部原因。 – ephemer

+0

謝謝!很有幫助。這是一個鏈接到沙盒與這對夫婦的更新工作,使解碼更容易一點。 http://swiftlang.ng.bluemix.net/#/repl/2dde62756a95d6d1c7bb88068cb35ebfe4b13ffc3ec891856992166caa8a291d – Pat

+0

您使用的詞語「編碼」和「解碼」的是我如何看待字符串和UTF-8的數據之間進行轉換相反。 – RenniePet

0

我一直在尋找一個全面的答案在Swift我自己的字符串操作。依靠鑄造NSString和其他不安全的指針魔術就是不適合我。這裏是一個安全的選擇:

首先,我們要擴展UInt8。這是CodeUnit後面的原始類型。

extension UInt8 { 
    var character: Character { 
     return Character(UnicodeScalar(self)) 
    } 
} 

這將使我們能夠做這樣的事情:

let codeUnits: [UInt8] = [ 
    72, 69, 76, 76, 79 
] 

let characters = codeUnits.map { $0.character } 
let string  = String(characters) 

// string prints "HELLO" 

配備了這個擴展,我們現在正在修改字符串。

let string = "ABCDEFGHIJKLMONP" 

var modifiedCharacters = [Character]() 
for (index, utf8unit) in string.utf8.enumerate() { 

    // Insert a "-" every 4 characters 
    if index > 0 && index % 4 == 0 { 
     let separator: UInt8 = 45 // "-" in ASCII 
     modifiedCharacters.append(separator.character) 
    } 
    modifiedCharacters.append(utf8unit.character) 
} 

let modifiedString = String(modifiedCharacters) 

// modified string == "ABCD-EFGH-IJKL-MONP" 
+0

我是否正確地認爲這隻適用於ASCII字符串?也就是說,如果字符串中有丹麥字母?它會攪亂一切?或重音字母?且不說其他字母像俄羅斯西里爾和希臘字母和中國及... – RenniePet

+0

是的,這個假設是正確的。此解決方案僅適用於單字節(ASCII)字符,並且會迅速打破錶情符號或國際字符等任何內容。 – dbart

0

有雨燕3.0的版本Martin R答案

public class UTF8Encoding { 
    public static func encode(bytes: Array<UInt8>) -> String { 
    var encodedString = "" 
    var decoder = UTF8() 
    var generator = bytes.makeIterator() 
    var finished: Bool = false 
    repeat { 
     let decodingResult = decoder.decode(&generator) 
     switch decodingResult { 
     case .scalarValue(let char): 
     encodedString += "\(char)" 
     case .emptyInput: 
     finished = true 
     case .error: 
     finished = true 
     } 
    } while (!finished) 
    return encodedString 
    } 
    public static func decode(str: String) -> Array<UInt8> { 
    var decodedBytes = Array<UInt8>() 
    for b in str.utf8 { 
     decodedBytes.append(b) 
    } 
    return decodedBytes 
    } 
} 

如果你想顯示從UTF-8字符串的表情符號,只是用戶convertEmojiCodesToString低於方法。這是正常的像「U + 1F52B」(表情符)的字符串或「U + 1F1E6 U + 1F1F1」(國國旗的表情符號)

class EmojiConverter { 
    static func convertEmojiCodesToString(_ emojiCodesString: String) -> String { 
    let emojies = emojiCodesString.components(separatedBy: " ") 
    var resultString = "" 
    for emoji in emojies { 
     var formattedCode = emoji 
     formattedCode.slice(from: 2, to: emoji.length) 
     formattedCode = formattedCode.lowercased() 
     if let charCode = UInt32(formattedCode, radix: 16), 
     let unicode = UnicodeScalar(charCode) { 
     let str = String(unicode) 
     resultString += "\(str)" 
     } 
    } 
    return resultString 
    } 
} 
1

斯威夫特3

let s = String(bytes: arr, encoding: .utf8)

1

如果您從原始緩衝區開始,例如從文件句柄返回的數據對象(在本例中,取自管道對象):

let data = pipe.fileHandleForReading.readDataToEndOfFile() 
var unsafePointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count) 

data.copyBytes(to: unsafePointer, count: data.count) 

let output = String(cString: unsafePointer)