Dans votre exemple, vos mots sont uniques, et vous pouvez utiliser la méthode suivante:
let myString = "word1 word2 word3"
let wordNum = 2
let myRange = myString.rangeOfString(myString.componentsSeparatedByString(" ")[wordNum-1])
// 6..<11
Comme l'a souligné Andrew Duncan dans les commentaires ci-dessous, ce qui précède est valable uniquement si vos mots sont uniques. Si vous avez des mots non uniques, vous pouvez utiliser cette méthode un peu moins plus propre:
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
let arr = myString.componentsSeparatedByString(" ")
var fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + wordNum - 1
let myRange = Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
let myWord = myString.substringWithRange(myRange)
// string "word1" (from range 36..<41)
Enfin, permet d'utiliser ce dernier pour construire une extension de String
que vous avez souhaité dans votre exemple de question:
extension String {
private func rangeOfNthWord(wordNum: Int, wordSeparator: String) -> Range<String.Index>? {
let arr = myString.componentsSeparatedByString(wordSeparator)
if arr.count < wordNum {
return nil
}
else {
let fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + (wordNum - 1)*wordSeparator.characters.count
return Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
}
}
}
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
if let myRange = myString.rangeOfNthWord(wordNum, wordSeparator: " ") {
// myRange: 36..<41
print(myString.substringWithRange(myRange)) // prints "word1"
}
Vous pouvez modifier la méthode .rangeOfNthWord(...)
si la séparation des mots n'est pas unique (par exemple, certains mots sont séparés par deux espaces vides " "
).
a également souligné dans les commentaires ci-dessous, l'utilisation de .rangeOfString(...)
n'est pas, en soi, pur Swift. Ce n'est cependant pas une mauvaise pratique. De Swift Language Guide - Strings and Characters:
Le type de chaîne de Swift est ponté avec la classe NSString de Foundation. Si vous travaillez avec le framework Foundation dans Cocoa, l'intégralité de l'API NSString est disponible pour appeler toute valeur de chaîne que vous créez lorsque le type est transtypé en NSString, comme décrit dans AnyObject. Vous pouvez également utiliser une valeur de chaîne avec n'importe quelle API nécessitant une instance NSString.
Voir aussi la NSString class reference for rangeOfString method:
// Swift Declaration:
func rangeOfString(_ searchString: String) -> NSRange
Ce n'est pas vraiment un "lexer" que vous implémentez! – Noldorin
Salut, Andrew - Connaissez-vous NSLinguisticTagger? - Ou, dans votre exemple plutôt simple, NSRegularExpression ne serait-il pas suffisant? – matt
Vous savez, en tant que (ancien) Perl hacker, j'aurais dû penser à REs. Bien que je ne sois pas intéressé par trouver le mot Nième, mais trouver sa gamme. Est-ce que je pourrais faire ça avec un RE? Ce n'est pas une pure ER informatique, bien sûr, mais peut-être même des améliorations. –