В вашем примере, ваши слова являются уникальными, и вы можете использовать следующий метод:
let myString = "word1 word2 word3"
let wordNum = 2
let myRange = myString.rangeOfString(myString.componentsSeparatedByString(" ")[wordNum-1])
// 6..<11
Как указал, Эндрю Дункан в комментариях ниже, выше, действует только тогда, когда ваши слова являются уникальными. Если у вас есть не-уникальные слова, вы можете использовать это несколько меньше, аккуратнее метод:
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)
Наконец, позволяет использовать последний построить расширение String
как вы желали в вашем примере вопроса:
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"
}
Вы можете настроить метод .rangeOfNthWord(...)
, если разделение слов не является уникальным (например, некоторые слова разделены двумя пробелами " "
).
Кроме того, отметил в комментариях ниже, использование .rangeOfString(...)
не является, по сути, чистый Swift. Это, однако, отнюдь не плохая практика. От Swift Language Guide - Strings and Characters:
Строка типа Swift соединена с классом NSString Foundation. Если вы работаете с базой Foundation в Cocoa, весь API NSString доступен для вызова любого строкового значения, которое вы создаете, когда тип применяется к NSString, как описано в AnyObject. Вы также можете использовать значение строки с любым API, для которого требуется экземпляр NSString.
Смотрите также NSString class reference for rangeOfString method:
// Swift Declaration:
func rangeOfString(_ searchString: String) -> NSRange
Это вряд ли «лексер», который вы будете внедрять! – Noldorin
Привет, Андрей - Вы знаете о NSLinguisticTagger? - Или, в вашем довольно простодушном примере, недостаточно ли было бы NSRegularExpression? – matt
Вы знаете, как (бывший) хакер Perl, я должен был подумать о REs. Хотя мне не интересно просто найти N-е слово, но найти его диапазон. Могу ли я сделать это с помощью RE? Конечно, не чистая компьютерная наука, но, возможно, с улучшенными. –