2014-09-29 62 views
10

Swift似乎試圖反對一個由原子字符數組組成的字符串的概念,這對於許多用途而言是有意義的,但是有很多編程涉及通過ASCII實現所有實際目的的數據結構:特別是文件I/O。指定字符文字沒有內置的語言特性似乎是一個很大的漏洞,即不存在C/Java的的/ etc式的模擬:是否有一種乾淨的方式來指定Swift中的字符文字?

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

這是相當不方便的,因爲即使你將您的字符串轉換爲字符數組,你不能做這樣的事情:

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

一個相當哈克的解決辦法是做這樣的事情:

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

這工作,但很明顯,這很醜陋。有沒有人有更好的方法?

回答

10

Character s可以從String s創建,只要那些String s只由單個字符組成。而且,由於Character實現了ExtendedGraphemeClusterLiteralConvertible,因此Swift會自動爲您分配任務。所以,要創建在斯威夫特一個Character,你可以簡單地這樣做:

let ch: Character = "a" 

然後,你可以使用一個IntervalType(與Range operators生成)contains方法檢查字符是否該範圍內你正在尋找用於:

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

實施例:

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

輸出:

沒錯


更新:作爲@MartinR指出,斯威夫特字符排序基於Unicode Normalization Form D這是以相同的順序爲ASCII字符代碼不。在您的特定情況下,在az之間的字符數多於直接ASCII(例如,ä)。有關更多信息,請參閱@ MartinR的回答here

如果您需要檢查一個字符是否在兩個ASCII字符代碼之間,那麼您可能需要執行類似於原始解決方法的操作。不過,你還必須ch轉換爲unichar而不是Character爲它工作(見this question更多信息上Character VS 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") 
} 

注:兩者的這些例子只是作爲我們僅限於工作,如果角色只包含一個單一的代碼點,但是,只要SCII,這應該不成問題。

+0

請注意,Swift字符串或字符的排序不基於ASCII碼(比較http://stackoverflow.com/a/25775112/1187415)。例如''a「...」z「'包含字符」ä「。這可能是需要的或不需要。 – 2014-09-29 19:32:54

+0

@MartinR謝謝,我沒有意識到這一點。我用這個信息更新了答案。 – 2014-09-29 21:32:05

+0

這是一個很好的訣竅,我會在銀行裏爲其他類型的邏輯保留。儘管如此,仍然有點高:當談到char-by-char文件格式解析時,性能和精度一樣重要,不能替代能夠在類int和類字符之間來回切換一個人物。所以char-literal仍然是需要的。 – 2014-09-29 22:14:29

6

如果您需要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) 

所有這些初始值將在編譯時評估,所以它確實是你在彙編指令級別立即文字表達。

相關問題