Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 查找字符串中搜索项的所有索引_String_Swift - Fatal编程技术网

String 查找字符串中搜索项的所有索引

String 查找字符串中搜索项的所有索引,string,swift,String,Swift,我需要一个快速的方法来查找可能出现在字符串中的搜索项的所有索引。我尝试了这种“蛮力”Stringextension方法: // Note: makes use of ExSwift extension String { var length: Int { return count(self) } func indicesOf(searchTerm:String) -> [Int] { var indices = [Int]() for i

我需要一个快速的方法来查找可能出现在字符串中的搜索项的所有索引。我尝试了这种“蛮力”
String
extension方法:

// Note: makes use of ExSwift
extension String
{
    var length: Int { return count(self) }

    func indicesOf(searchTerm:String) -> [Int] {
        var indices = [Int]()
        for i in 0 ..< self.length {
            let segment = self[i ... (i + searchTerm.length - 1)]
            if (segment == searchTerm) {
                indices.append(i)
            }
        }
        return indices;
    }
}
//注意:使用ExSwift
扩展字符串
{
变量长度:Int{return count(self)}
func indicatesof(searchTerm:String)->[Int]{
var指数=[Int]()
对于0中的i..

。。。但它的速度慢得可笑,尤其是搜索词越短。快速查找所有索引的更好方法是什么?

而不是在字符串的每个位置检查搜索词 您可以使用
rangeOfString()
查找下一个事件(如有)
rangeOfString()
使用了更高级的算法):

扩展字符串{
func indicatesof(searchTerm:String)->[Int]{
var指数=[Int]()
var pos=自启动索引
而let range=self.rangeOfsString(搜索词,范围:pos.
通常,它取决于输入字符串的大小和大小 搜索字符串的“最快”算法。你会发现 中的各种算法链接的概述

更新Swift 3:

extension String {

    func indices(of searchTerm:String) -> [Int] {
        var indices = [Int]()
        var pos = self.startIndex
        while let range = range(of: searchTerm, range: pos ..< self.endIndex) {
            indices.append(distance(from: startIndex, to: range.lowerBound))
            pos = index(after: range.lowerBound)
        }
        return indices
    }
}
扩展字符串{
func索引(搜索项的:字符串)->[Int]{
var指数=[Int]()
var pos=自启动索引
而let range=range(of:searchTerm,range:pos..
正如Martin所说,您可以实现一些众所周知的字符串匹配最快算法,字符串搜索算法(或KMP算法)搜索主“文本字符串”
S
中出现的“单词”
W

该算法具有复杂性,其中n是
S
的长度,O是

a输出应为:

[14, 27]
属于字符串中模式引用的开始索引的。我希望这对你有帮助

编辑:

extension String {

    func indices(of searchTerm:String) -> [Int] {
        var indices = [Int]()
        var pos = self.startIndex
        while let range = range(of: searchTerm, range: pos ..< self.endIndex) {
            indices.append(distance(from: startIndex, to: range.lowerBound))
            pos = index(after: range.lowerBound)
        }
        return indices
    }
}
正如Martin在评论中所说,您需要避免使用
advance
函数通过
Int
索引
字符串,因为它是O(索引位置)

一种可能的解决方案是将
字符串
转换为
字符数组
,然后访问索引是O(1)

然后可以将
扩展名更改为此扩展名:

extension String {

   // Build pi function of prefixes
   private func build_pi(str: [Character]) -> [Int] {

      var n = count(str)
      var pi = Array(count: n + 1, repeatedValue: 0)
      var k = -1
      pi[0] = -1

      for (var i = 0; i < n; ++i) {
          while (k >= 0 && str[k] != str[i]) {
              k = pi[k]
          }
          pi[i + 1] = ++k
      }

      return pi
   }

   // Knuth-Morris Pratt algorithm
   func searchPattern(pattern: String) -> [Int] {

      // Convert to Character array to index in O(1)
      var patt = Array(pattern)
      var S = Array(self)

      var matches = [Int]()
      var n = count(self)

      var m = count(pattern)
      var k = 0
      var pi = build_pi(patt)

      for var i = 0; i < n; ++i {
         while (k >= 0 && (k == m || patt[k] != S[i])) {
             k = pi[k]
         }
         if ++k == m {
             matches.append(i - m + 1)
         }
      }

      return matches
   }
}
扩展字符串{
//构建前缀的pi函数
私有函数构建_pi(str:[字符])->[Int]{
变量n=计数(str)
var pi=数组(计数:n+1,重复值:0)
变量k=-1
pi[0]=-1
对于(变量i=0;i=0&&str[k]!=str[i]){
k=pi[k]
}
pi[i+1]=++k
}
返回pi
}
//Knuth-Morris-Pratt算法
func searchPattern(模式:字符串)->[Int]{
//将字符数组转换为O(1)中的索引
var patt=阵列(模式)
var S=数组(自身)
变量匹配=[Int]()
var n=计数(自身)
var m=计数(模式)
var k=0
var pi=构建_pi(patt)
对于变量i=0;i=0&(k==m | | patt[k]!=S[i])){
k=pi[k]
}
如果++k==m{
匹配。追加(i-m+1)
}
}
复赛
}
}

使用Swift 4中的NSRegularExpression,您可以这样做
NSRegularExpression
已经存在很久了,在大多数情况下,它可能是比使用自己的算法更好的选择

let text = "The quieter you become, the more you can hear."
let searchTerm = "you"

let regex = try! NSRegularExpression(pattern: searchTerm, options: [])
let range: NSRange = NSRange(text.startIndex ..< text.endIndex, in: text)
let matches: [NSTextCheckingResult] = regex.matches(in: text, options: [], range: range)
let ranges: [NSRange] = matches.map { $0.range }
let indices: [Int] = ranges.map { $0.location }
let swiftRanges = ranges.map { Range($0, in: text) }
let swiftIndices: [String.Index] = swiftRanges.flatMap { $0?.lowerBound }
let text=“你越安静,听到的声音就越多。”
让searchTerm=“您”
让regex=试试!NSRegularExpression(模式:searchTerm,选项:[])
let range:NSRange=NSRange(text.startIndex..
您使用的是哪个Xcode版本?您的代码不在Xcode 6.3.2或Xcode 7 beta.Xcode 6.3.2中编译。也许你缺了线,长度
var-length:Int{return count(self)}
String在我的Xcode 6.3.2中没有属性长度(而且不能用整数为字符串下标)。也许您正在使用一些扩展?我更新了代码,使其有意义。哦,对了,订阅。。。我使用ExSwift。你的方法要快得多,我测试的文本有1000到2000个字符。谢谢你的解决方案。我可以再把regexp实验放回抽屉里。@Martin R代替index.append(距离(从:startIndex,到:range.lowerBound))是不是ArrayFindices.append(range.lowerBound.encodedOffset)更快?@VYT:可能是,但它给出的结果不同。试试
“@Martin R是的,对于表情符号来说这是不好的。(我没有在表情符号中使用字符串的代码)。注意
advance(self.startIndex,I)
对于字符串在O(I)中执行,因此也必须考虑到这一点。如果可能的话,最好使用
String.Index
而不是
Int
索引。是的,你是对的@MartinR我会更新我的答案。感谢你的观察。我做了一些简单的性能测试,你更新的代码比ori快大约250倍
extension String {

   // Build pi function of prefixes
   private func build_pi(str: [Character]) -> [Int] {

      var n = count(str)
      var pi = Array(count: n + 1, repeatedValue: 0)
      var k = -1
      pi[0] = -1

      for (var i = 0; i < n; ++i) {
          while (k >= 0 && str[k] != str[i]) {
              k = pi[k]
          }
          pi[i + 1] = ++k
      }

      return pi
   }

   // Knuth-Morris Pratt algorithm
   func searchPattern(pattern: String) -> [Int] {

      // Convert to Character array to index in O(1)
      var patt = Array(pattern)
      var S = Array(self)

      var matches = [Int]()
      var n = count(self)

      var m = count(pattern)
      var k = 0
      var pi = build_pi(patt)

      for var i = 0; i < n; ++i {
         while (k >= 0 && (k == m || patt[k] != S[i])) {
             k = pi[k]
         }
         if ++k == m {
             matches.append(i - m + 1)
         }
      }

      return matches
   }
}
let text = "The quieter you become, the more you can hear."
let searchTerm = "you"

let regex = try! NSRegularExpression(pattern: searchTerm, options: [])
let range: NSRange = NSRange(text.startIndex ..< text.endIndex, in: text)
let matches: [NSTextCheckingResult] = regex.matches(in: text, options: [], range: range)
let ranges: [NSRange] = matches.map { $0.range }
let indices: [Int] = ranges.map { $0.location }
let swiftRanges = ranges.map { Range($0, in: text) }
let swiftIndices: [String.Index] = swiftRanges.flatMap { $0?.lowerBound }