从控制台读取数据在F#中的实现

14

有没有内置函数可以像printfn一样从控制台读取输入?我只看到过使用System.Console.Read()的方法,但它不如使用printfn方便。

3个回答

18

很遗憾,没有这样的内置函数。然而,正如Brian在Benjol答案的评论中提到的那样,可以自己构建一个scanf函数。下面是一个快速草图,展示了如何定义一个sscanf变体,尽管只实现了%s占位符:

open System
open System.Text
open System.Text.RegularExpressions
open Microsoft.FSharp.Reflection

let sscanf (pf:PrintfFormat<_,_,_,_,'t>) s : 't =
  let formatStr = pf.Value
  let constants = formatStr.Split([|"%s"|], StringSplitOptions.None)
  let regex = Regex("^" + String.Join("(.*?)", constants |> Array.map Regex.Escape) + "$")
  let matches = 
    regex.Match(s).Groups 
    |> Seq.cast<Group> 
    |> Seq.skip 1
    |> Seq.map (fun g -> g.Value |> box)
  FSharpValue.MakeTuple(matches |> Seq.toArray, typeof<'t>) :?> 't


let (a,b) = sscanf "(%s, %s)" "(A, B)"
let (x,y,z) = sscanf "%s-%s-%s" "test-this-string"

8
当我需要一个更完整的sscanf版本时,扩展这段代码非常容易。请在此处查看结果:http://fssnip.net/4I - wmeyer
@wmeyer:你有兴趣将这个贡献给FSharpx吗?https://github.com/fsharp/fsharpx - Mauricio Scheffer
@wmeyer 这个实现的问题在于,当你只有一个元素时它不能很好地工作,因为这时 MakeTuple 会出错... - Rei Miyasaka
3
快速修复:将最后的 MakeTuple 行替换为:if matches.Length = 1 then matches.[0] :?> 't; else FSharpValue.MakeTuple(matches, typeof<'t>) :?> 't - Rei Miyasaka
@Rei:酷!如果你想的话,你甚至可以直接在fssnip上修复它!(我认为) - wmeyer
@wmeyer 哦,没注意到。完成了! - Rei Miyasaka

1
据我所知,不行。
这对于代码高尔夫来说会很方便 :)

3
可惜的是,printfn 函数本身依赖于编译器的魔法 - 你不能像它那样轻松地编写自己的 F# sscanf 函数。 - Tim Robinson
4
你可以做到,我相信。唯一的魔法是字符串文字可以被强制转换为PrintfFormats,此时类型就变得明显了:let pf() : PrintfFormat< _ , _ , _ , _ > = "%d %s" - Brian

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接