我需要将一个字符串转换为一个没有内置函数的单词列表,这是我到目前为止所做的,显然是错误的:
let rec convert word =
match word with
|"." ->[]
|word -> ["word"]
|word + " " + words -> [word]@convert words
Run Code Online (Sandbox Code Playgroud)
由于你的问题有点学术性,我会分别接近解决方案.
暂时搁置不使用内置库的要求,解决方案可能会遵循经典的折叠模式,这种模式很容易从头开始实现,假设某些split属性稍后要实现:
let string2Words s =
let rec fold acc s =
match split s with
| [x] -> acc @ [x] // append the last word; done
| [head;tail] -> fold (acc @ [head]) tail // append the head word; continue splitting
| _ -> acc // done
fold [] s
Run Code Online (Sandbox Code Playgroud)
因此,我们的任务现在减少到实现split,接受一个字符串返回一个单词列表,或两个元素列表与头字和字符串的其余部分,或任何其他信号没有留下进一步拆分和时间就是交付结果.
使用的二元性string是一个char[]我们现在可以实现split依靠string索引和切片,而不是F#库库:
let split s =
let rec scan (s:string) i =
if s.Length = 0 then []
elif s.[i] = ' ' && i = 0 then scan s.[i+1..] 0
elif s.[i] = ' ' then [s.[..i-1]; s.[i+1..]]
elif i = (s.Length - 1) then [s]
else scan s (i+1)
scan s 0
Run Code Online (Sandbox Code Playgroud)
内部递归scan函数完成我们的fold(ab)使用字符串切片和索引器所期望的工作,并在路上考虑角点情况.
现在放在一起
let string2Words s =
let split s =
let rec scan (s:string) i =
if s.Length = 0 then []
elif s.[i] = ' ' && i = 0 then scan s.[i+1..] 0
elif s.[i] = ' ' then [s.[..i-1]; s.[i+1..]]
elif i = (s.Length - 1) then [s]
else scan s (i+1)
scan s 0
let rec fold acc s =
match split s with
| [x] -> acc @ [x]
| [head;tail] -> fold (acc @ [head]) tail
| _ -> acc
fold [] s
Run Code Online (Sandbox Code Playgroud)
并在fsi中快速检查:
> string2Words "life without libraries is tough";;
val it : string list = ["life"; "without"; "libraries"; "is"; "tough"]
Run Code Online (Sandbox Code Playgroud)