2014-12-29 4 views
31

Stellen Sie sich vor, Sie haben eine Instanz von Swifts Character Typ, und Sie möchten feststellen, ob es ein Mitglied einer NSCharacterSet ist. NSCharacterSet 's characterIsMember Methode dauert eine unichar, so müssen wir von Character bis unichar erhalten.NSCharacterSet.characterIsMember() mit Swifts Zeichen-Typ

Die einzige Lösung, die ich tun konnte, ist die folgende, wo c meine ist Character:

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

ich Character sah aber nichts sprang als eine Möglichkeit, um mich von ihm zu unichar zu bekommen. Dies kann daran liegen, dass Character allgemeiner ist als unichar, also wäre eine direkte Konvertierung nicht sicher, aber ich rate nur.

Wenn ich eine ganze Reihe laufen, würde ich so etwas tun:

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

(Achtung: Die obige Pseudo-Code und hat nie von niemandem geführt.) Aber das ist nicht wirklich das, was Ich frage.

Antwort

22

Mein Verständnis ist, dass unichar eine Typalias für UInt16 ist. A unichar ist nur eine Nummer.

Ich denke, dass das Problem, das Sie gegenüberstellen, ist, dass ein Character in Swift aus mehr als einem Unicode "Zeichen" bestehen kann. Daher kann es nicht in einen einzelnen unichar Wert konvertiert werden, da er aus zwei Unichars bestehen kann. - codeUnits - von unichar Werte

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

Dies wird produzieren eine Reihe: Sie können durch Gießen in einen String und mit Hilfe der utf16 Eigenschaft, wie dies eine Character in seine einzelnen unichar Werte zersetzen.

EDIT: Initial Code hatte for codeUnit in s wenn es for codeUnit in s.utf16

gewesen sein sollten Sie die Dinge und Prüfung für jeden einzelnen, ob oder nicht unichar Wert ist in einem Character Set wie folgt ordentlich kann:

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

Oder, wenn Sie nur an der ersten (und oft nur) unichar Wert interessiert sind:

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

Oder wickeln Sie es in einer Funktion:

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 

Nun ist die Funktionsprüfung für alleunichar Werte in einem zusammengesetzten Zeichen machen - diese Weise, wenn Sie ein zusammengesetztes Zeichen haben, wird die Funktion nur wahr zurück, wenn sowohl das Basiszeichen als auch das Kombinierzeichen sind vorhanden:

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 

Die letzte Version ist wichtig.Wenn Ihr Character ein zusammengesetztes Zeichen ist, müssen Sie prüfen, ob sowohl das Basiszeichen ("a") als auch das Kombinierzeichen (der akute Akzent) im Zeichensatz vorhanden ist, sonst erhalten Sie Fehlalarme.

+0

Das ist sehr interessant. Es löst mein Problem nicht genau, daher kann ich es nicht als Antwort bezeichnen, aber es erklärt, warum es keinen direkten "Charakter" -> "Unichar" gibt. –

+0

Ich habe meine Antwort etwas verfeinert. Seien Sie vorsichtig, dass die Antwort von matt, während eine gute Möglichkeit, nach nicht zusammengesetzten Zeichen zu suchen, für zusammengesetzte Zeichen möglicherweise nicht funktioniert. –

+0

Ich verdaue das immer noch. Faszinierend. –

12

Ich würde den Charakter als String behandeln und lasse Cocoa die ganze Arbeit tun:

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 
} 

Und hier ist, wie es zu benutzen:

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

Wie ich vermutet habe. Grundsätzlich müssen Sie 'Character' in' String' umwandeln, um dies zu tun. –

+0

Ich habe deinen Code schamlos gestohlen und ihn zu einer Erweiterungsmethode für 'NSCharacterSet' gemacht. –

+3

Dies kann vereinfacht werden zu 'let result = s.rangeOfCharacterFromSet (cset)' weil "options:" und "range:" (jetzt?) * Optionale * Parameter sind. –

2

Aufgrund von Änderungen in Swift 3.0, matt Antwort funktioniert nicht mehr, also hier ist die funktionierende Version (als Erweiterung):

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

Swift 3.0 Änderungen bedeutet Sie actu Verbünde nicht mehr zu NSCharacterSet Bridging, können Sie Swifts native CharacterSet verwenden.

Sie könnten direkt etwas Ähnliches wie Jiri Antwort tun:

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

oder tun:

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

Hinweis: Die oben genannten Abstürze und funktioniert nicht aufgrund https://bugs.swift.org/browse/SR-3667. Nicht sicher CharacterSet bekommt die Art von Liebe, die es braucht.

3

Haben sie alle in einem Motto:

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

(Swift 3)

Verwandte Themen