2016-04-26 4 views
0

У меня есть строка, например, «ad ad adk fda kla kad ab ab kd». Я хочу получить весь диапазон ab. (Здесь ab присутствует в 3 позиции, поэтому я должен получить 3 диапазона). В нормальном сценарии мой код работает нормально, но если текст поиска «.», То я получаю неправильный результатполучить все диапазоны подстроки в строке в swift

do { 
    let regEx = try NSRegularExpression(pattern: searchText, options: NSRegularExpressionOptions.CaseInsensitive) 

    let matchesRanges = regEx.matchesInString(attributedText.string, options:[], range: NSMakeRange(0, attributedText.string.length)) 

    for rng in matchesRanges { 
     let wordRange = rng.rangeAtIndex(0) 
    } 
} catch { 
    ... 
} 
+0

Вы должны показать, что вы уже пробовали и объясните, что он делает неправильно – Wain

+0

, пожалуйста, подробно объясните, какой результат вы хотите? – PSS

+0

«.» - это особый символ, означающий «Любой символ» – redent84

ответ

0

Вы можете получить вхождение рассчитывать на определенную строку по следующему коду:

let str: NSMutableString = "ab ad adk fda kla kad ab ab kd" 
let count = str.replaceOccurrencesOfString("ab", withString: "ab", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, str.length)) 
+0

Нет. Я хочу получить диапазоны, чтобы применять атрибуты на этих диапазонах. –

2

Я хотел бы предложить такое решение:

import Foundation 

extension String { 

    func rangesOfString(s: String) -> [Range<Index>] { 
     let re = try! NSRegularExpression(pattern: NSRegularExpression.escapedPatternForString(s), options: []) 
     return re.matchesInString(self, options: [], range: nsRange(startIndex ..< endIndex)).flatMap { range($0.range) } 
    } 

    func range(nsRange : NSRange) -> Range<Index>? { 
     let utf16from = utf16.startIndex.advancedBy(nsRange.location, limit: utf16.endIndex) 
     let utf16to = utf16from.advancedBy(nsRange.length, limit: utf16.endIndex) 

     if let from = String.Index(utf16from, within: self), 
      let to = String.Index(utf16to, within: self) 
     { 
      return from ..< to 
     } else { 
      return nil 
     } 
    } 

    func nsRange(range : Range<Index>) -> NSRange { 
     let utf16from = String.UTF16View.Index(range.startIndex, within: utf16) 
     let utf16to = String.UTF16View.Index(range.endIndex, within: utf16) 
     return NSRange(location: utf16.startIndex.distanceTo(utf16from), length: utf16from.distanceTo(utf16to)) 
    } 

} 

print("[^x]? [^x]? [^x]?".rangesOfString("[^x]?")) // [Range(0..<5), Range(6..<11), Range(12..<17)] 

Помимо основного вопрос, этот код также показывает путь для преобразования NSRange от Range<String.Index> (на основе this post).

+0

Заботится ли обо всех других специальных символах.? –

+0

Я использую [NSRegularExpression.escapedPatternForString()] (https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSRegularExpression_Class/#//apple_ref/occ/clm/NSRegularExpression/escapedPatternForString :), чтобы избежать каких-либо возможные метасимволы шаблона. Это должно быть надежным решением. – werediver

+0

Эти диапазоны <-> Конверсии NSRange выглядят знакомыми http://stackoverflow.com/a/30404532/1187415 :) –

1

Вы используете регулярные выражения, поэтому вам нужно позаботиться о персонажах, имеющих особое значение - . - это только один из них.

Если вы делаете поиск подстрок, я предлагаю использовать старый добрый rangeOf ... методы вместо:

func rangeOfString(_ searchString: String, 
      options mask: NSStringCompareOptions, 
      range searchRange: NSRange) -> NSRange 

Просто продолжают называть этот метод на вашей строки (и настроить searchRange), пока не будут найдены дальнейшие совпадения.

2

Следующее решение использует родную Swift 4 функции range(of:, options:, range:, locale:)):

extension String { 
    func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range<Index>] { 
     var ranges: [Range<Index>] = [] 
     while let range = self.range(of: substring, options: options, range: (ranges.last?.upperBound ?? self.startIndex)..<self.endIndex, locale: locale) { 
      ranges.append(range) 
     } 
     return ranges 
    } 
} 

(Swift-затем предоставляет родную API для преобразования из Range<Index> в NSRange)

+0

Это может привести к бесконечному циклу в некоторых ситуациях при использовании регулярного выражения. Проверьте этот ответ о том, как его избежать. Https://stackoverflow.com/a/32306142/2303865 –