2014-12-29 25 views
31

想象一下,你有一個斯威夫特的Character類型的實例,並且你想確定它是否是NSCharacterSet的成員。我們需要從CharacterunicharNSCharacterSet.characterIsMember()與斯威夫特的字符類型

唯一的解決辦法我能想出是以下,其中c是我Character

let u: unichar = ("\(c)" as NSString).characterAtIndex(0) 
if characterSet.characterIsMember(u) { 
    dude.abide() 
} 

我看着Character但沒有跳入我的眼簾,以此來得到它unichar。這可能是因爲Characterunichar更普遍,所以直接轉換並不安全,但我只是在猜測。

如果我是遍歷整個字符串,我會做這樣的事情:

let s = myString as NSString 
for i in 0..<countElements(myString) { 
    let u = s.characterAtIndex(i) 
    if characterSet.characterIsMember(u) { 
     dude.abide() 
    } 
} 

(警告:以上是僞的,從來沒有任何人曾經遇到。)但是,這是不是真的什麼我在問。

回答

22

我的理解是,unicharUInt16的一個typealias。 A unichar只是一個數字。

我認爲你面臨的問題是Swift中的Character可能由多個unicode「字符」組成。因此,它不能被轉換爲單個值,因爲它可能由兩個unichars組成。您可以通過其強制轉換爲字符串並使用utf16屬性,這樣一個分解成Character其個人unichar值:

let c: Character = "a" 
let s = String(c) 
var codeUnits = [unichar]() 
for codeUnit in s.utf16 { 
    codeUnits.append(codeUnit) 
} 

這將產生一個數組 - codeUnits - unichar值。

編輯:初始代碼有for codeUnit in s時,它應該是for codeUnit in s.utf16

你可以收拾東西和測試爲每個unichar值是否是在一個字符集是這樣的:

let char: Character = "\u{63}\u{20dd}" // This is a 'c' inside of an enclosing circle 
for codeUnit in String(char).utf16 { 
    if NSCharacterSet(charactersInString: "c").characterIsMember(codeUnit) { 
     dude.abide() 
    } // dude will abide() for codeUnits[0] = "c", but not for codeUnits[1] = 0x20dd (the enclosing circle) 
} 

或者,如果您只對第一個(通常只有)unichar值有興趣:

if NSCharacterSet(charactersInString: "c").characterIsMember(String(char).utf16[0]) { 
    dude.abide() 
} 

或者,在一個函數把它包:

func isChar(char: Character, inSet set: NSCharacterSet) -> Bool { 
    return set.characterIsMember(String(char).utf16[0]) 
} 

let xSet = NSCharacterSet(charactersInString: "x") 
isChar("x", inSet: xSet) // This returns true 
isChar("y", inSet: xSet) // This returns false 

現在做出功能檢查中的一個組成字符的所有unichar值 - 這樣一來,如果你有一個組合字符,該函數將只返回如果屬實這兩個基本字符和組合字符存在:

func isChar(char: Character, inSet set: NSCharacterSet) -> Bool { 
    var found = true 
    for ch in String(char).utf16 { 
     if !set.characterIsMember(ch) { found = false } 
    } 
    return found 
} 

let acuteA: Character = "\u{e1}"     // An "a" with an accent 
let acuteAComposed: Character = "\u{61}\u{301}" // Also an "a" with an accent 

// A character set that includes both the composed and uncomposed unichar values 
let charSet = NSCharacterSet(charactersInString: "\u{61}\u{301}\u{e1}") 

isChar(acuteA, inSet: charSet)   // returns true 
isChar(acuteAComposed, inSet: charSet) // returns true (both unichar values were matched 

的最後一個版本是非常重要的。如果您的Character是一個組成字符,您必須檢查字符集中是否存在基本字符(「a」)和組合字符(尖銳重音),否則您將得到誤報。

+0

這是非常有趣的。它不能完全解決我的問題,所以我不能將其標記爲答案,但它確實解釋了爲什麼沒有直接的'Character' - >'unichar'。 –

+0

我細化了我的答案。注意亞光的答案,而檢查非組成字符的好方法可能不適用於組成字符。 –

+0

我仍在消化這一點。迷人。 –

12

我會像對待字符作爲字符串,讓可可做所有的工作:

func charset(cset:NSCharacterSet, containsCharacter c:Character) -> Bool { 
    let s = String(c) 
    let ix = s.startIndex 
    let ix2 = s.endIndex 
    let result = s.rangeOfCharacterFromSet(cset, options: nil, range: ix..<ix2) 
    return result != nil 
} 

這裏是如何使用它:

let cset = NSCharacterSet.lowercaseLetterCharacterSet() 
let c : Character = "c" 
let ok = charset(cset, containsCharacter:c) // true 
+0

正如我懷疑。基本上,你必須把'Character'變成'String'才能做到這一點。 –

+0

我無恥地竊取了你的代碼,並把它變成了'NSCharacterSet'上的擴展方法。 –

+3

這可以簡化爲'let result = s.rangeOfCharacterFromSet(cset)',因爲「options:」和「range:」是(now?)* optional *參數。 –

2

由於雨燕3.0,馬特的答案改變不再起作用,所以這裏工作版本(如擴展名):

private extension NSCharacterSet { 

    func containsCharacter(c: Character) -> Bool { 

     let s = String(c) 
     let ix = s.startIndex 
     let ix2 = s.endIndex 
     let result = s.rangeOfCharacter(from: self as CharacterSet, options: [], range: ix..<ix2) 
     return result != nil 
    } 
} 
0

雨燕3.0的改變意味着你ACTU盟友不需要再橋接到NSCharacterSet了,您可以使用Swift的本地CharacterSet

你可以做一些類似吉日的直接回答了一句:

extension CharacterSet { 
    func contains(_ character: Character) -> Bool { 
     let string = String(character) 
     return string.rangeOfCharacter(from: self, options: [], range: string.startIndex..<string.endIndex) != nil 
    } 
} 

或做:

func contains(_ character: Character) -> Bool { 
    let otherSet = CharacterSet(charactersIn: String(character)) 
    return self.isSuperset(of: otherSet) 
} 

注:以上崩潰,無法正常工作,由於https://bugs.swift.org/browse/SR-3667。不知道CharacterSet得到它需要的那種愛。

3

做這一切的一個襯:

validCharacterSet.contains(String(char).unicodeScalars.first!) 

(SWIFT 3)