2016-12-03 1 views
0

Je veux avoir plusieurs groupes de capture qui peuvent être optionnels et je veux accéder aux chaînes auxquelles ils correspondent.groupes de capture optionnels avec NSRegularExpressions dans swift

Quelque chose qui ressemble/fonctionne comme ceci:

let text1 = "something with foo and bar" 
let text2 = "something with just bar" 
let regex = NSRegularExpression(pattern: "(foo)? (bar)") 

for (first?, second) in regex.matches(in:text1) { 
    print(first) // foo 
    print(second) // bar 
} 

for (first?, second) in regex.matches(in:text2) { 
    print(first) // nil 
    print(second) // bar 
} 

Répondre

1

Récupération sous-texte capturé avec NSRegularExpression est pas si facile.

Tout d'abord, le résultat de matches(in:range:) est [NSTextCheckingResult], et chaque NSTextCheckingResult ne correspond pas à tuple comme (first?, second).

Si vous souhaitez récupérer un sous-texte capturé, vous devez obtenir la plage de la méthode NSTextCheckingResult avec rangeAt(_:). rangeAt(0) représente la plage correspondant à l'ensemble du modèle, rangeAt(1) pour la première capture, rangeAt(2) pour la seconde, et ainsi de suite.

Et rangeAt(_:) renvoie NSRange, pas Swift Range. Le contenu (location et length) est basé sur la représentation UTF-16 de NSString.

Et ceci est la partie la plus importante pour votre usage, rangeAt(_:) renvoie NSRange(location: NSNotFound, length: 0) pour chaque capture manquante.

Ainsi, vous devrez peut-être écrire quelque chose comme ceci:

let text1 = "something with foo and bar" 
let text2 = "something with just bar" 
let regex = try! NSRegularExpression(pattern: "(?:(foo).*)?(bar)") //please find a better example... 

for match in regex.matches(in: text1, range: NSRange(0..<text1.utf16.count)) { 
    let firstRange = match.rangeAt(1) 
    let secondRange = match.rangeAt(2) 
    let first = firstRange.location != NSNotFound ? (text1 as NSString).substring(with: firstRange) : nil 
    let second = (text1 as NSString).substring(with: secondRange) 
    print(first) // Optioonal("foo") 
    print(second) // bar 
} 

for match in regex.matches(in: text2, range: NSRange(0..<text2.utf16.count)) { 
    let firstRange = match.rangeAt(1) 
    let secondRange = match.rangeAt(2) 
    let first = firstRange.location != NSNotFound ? (text2 as NSString).substring(with: firstRange) : nil 
    let second = (text2 as NSString).substring(with: secondRange) 
    print(first) // nil 
    print(second) // bar 
}