子串索引

时间:2011-03-02 14:43:27

标签: f# substring

我对F#很新。我编写了一个函数,它返回目标中子字符串匹配索引的数组,它类似于我在C#中编写的方式。

是否有更实用的方法来解决这个问题,是否可以在不使用任何可变变量的情况下解决?

let SubStringIndices (haystack:string) (needle:string) =
    let mutable indices = System.Collections.Generic.List<int>()
    let mutable index = haystack.IndexOf(needle)
    while index >= 0 do
        indices.Add(index)
        index <- haystack.IndexOf(needle, index+1)
    indices.ToArray()

printfn "%A" (SubStringIndices  "abaabababaaab" "ab")
// prints [|0; 3; 5; 7; 11|]

我不是在寻找在每个索引处检查子字符串匹配的解决方案。

2 个答案:

答案 0 :(得分:4)

这是一个简单的递归函数,可以执行相同的操作:

let rec subStringIndices (haystack:string) (needle:string) (from:int) =
  let index = haystack.IndexOf(needle, from)
  if index >= 0 then 
    let rest = subStringIndices haystack needle (index + 1)
    index::rest
  else []

printfn "%A" (subStringIndices  "abaabababaaab" "ab" 0)

该函数采用另一个参数from来表示起始索引(您希望在字符串中开始搜索的位置)。最初,将其设置为零。在函数中,我们首先得到下一个索引。如果我们找到了某些东西,我们递归处理字符串的其余部分(从index + 1开始)并返回一个包含索引和所有递归索引的列表。

使用累加器参数技巧和嵌套函数可以编写使用 tail-recursion 的更优雅,更高效的版本:

let subStringIndices (haystack:string) (needle:string) =
  let rec loop (from:int) acc =
    let index = haystack.IndexOf(needle, from)
    if index >= 0 then 
      loop (index + 1) (index::acc)
    else
      List.rev acc
  loop 0 []

递归循环现在由loop函数实现。它从外部获取haystackneedle作为参数,因此不需要在堆栈中复制这些参数。我们在作为参数传递的acc列表中累积索引,当我们到达结尾时,我们返回列表(相反,因为我们在前面添加了新项目)。

答案 1 :(得分:4)

类似

let SubStringIndices (haystack:string) (needle:string) = 
    -1 |> Seq.unfold (fun n -> 
        let idx = haystack.IndexOf(needle, n + 1)
        if idx <> -1 then Some(idx, idx) else None        
        )