如何将字符串转换为F#中的列表单词

Bad*_*sef 1 string f# list

我需要将一个字符串转换为一个没有内置函数的单词列表,这是我到目前为止所做的,显然是错误的:

let rec convert word = 
    match word with
    |"."      ->[]
    |word -> ["word"]
    |word + " " + words -> [word]@convert words
Run Code Online (Sandbox Code Playgroud)

Gen*_*ski 6

由于你的问题有点学术性,我会分别接近解决方案.

暂时搁置不使用内置库的要求,解决方案可能会遵循经典的折叠模式,这种模式很容易从头开始实现,假设某些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)