F#删除尾随空格

时间:2016-09-29 23:29:31

标签: f# functional-programming

我有这个方法,它接受一个列表并将其转换为字节码字符串。它的工作方式与我期望的一样;但是,我得到一个我不想要的尾随空间。 问题:如何摆脱最后一次追踪0?

Input: byteCode [SC 10; SC 2; SAdd; SC 32; SC 4; SC 5; SAdd; SMul; SAdd]

let rec byteCode (l : sInstr list) : string = 
  match l with 
  | [] -> "" 
  | (SC    n :: l)     -> "0 " + string n + " " + byteCode l 
  | (SAdd    :: l)     -> "1 " + byteCode l 
  | (SSub    :: l)     -> "2 " + byteCode l 
  | (SMul    :: l)     -> "3 " + byteCode l 
  | (SNeg    :: l)     -> "4 " + byteCode l 
  | (SLess   :: l)     -> "5 " + byteCode l 
  | (SIfze n :: l)     -> "6 " + string n + " " + byteCode l 
  | (SJump n :: l)     -> "7 " + string n + " " + byteCode l

这可能不会编译,因为我没有给出我的整个程序。

This returns: "0 10 0 2 1 0 32 0 4 0 5 1 3 1 "
I expect:     "0 10 0 2 1 0 32 0 4 0 5 1 3 1"

2 个答案:

答案 0 :(得分:7)

这样的案例通常表明字符串以过于幼稚的方式连接起来。首先考虑收集结果的所有单个组件,然后调用预定义的String.concat函数:

let byteCode (l : sInstr list) : string = 
    let rec byteCode' l =
        match l with 
        | [] -> []
        | (SC    n :: l)     -> "0" :: string n :: byteCode' l
        | (SAdd    :: l)     -> "1" :: byteCode' l
        | (SSub    :: l)     -> "2" :: byteCode' l
        | (SMul    :: l)     -> "3" :: byteCode' l
        | (SNeg    :: l)     -> "4" :: byteCode' l
        | (SLess   :: l)     -> "5" :: byteCode' l
        | (SIfze n :: l)     -> "6" :: string n :: byteCode' l 
        | (SJump n :: l)     -> "7" :: string n :: byteCode' l

    l |> byteCode' |> String.concat " "

String.concat已经只在各个部分之间添加了分隔符字符串

这也更清晰,因为它将特定分隔符字符串的实现细节保留在核心逻辑之外,并使其更容易替换 - 想象一下将函数简单地更改为函数中的两个空格的努力。

或者,您可以只使用现有函数,并在最终生成的字符串上调用.Trim()(或.TrimEnd())方法来删除(尾随)空格。

答案 1 :(得分:2)

你可以用这种方式避免递归:

let byteCode (l : sInstr list) : string = 
  let instrToString (bc : sInstr) : string =
    match bc with 
    | (SC    n) -> sprintf "0 %d" n
    | (SAdd   ) -> "1"
    | (SSub   ) -> "2"
    | (SMul   ) -> "3"
    | (SNeg   ) -> "4"
    | (SLess  ) -> "5"
    | (SIfze n) -> sprintf "6 %d" n
    | (SJump n) -> sprintf "7 %d" n

  l |> List.map instrToString |> String.concat " "

假设sInstr定义为:

type sInstr =
| SC of int
| SAdd
| SSub
| SMul
| SNeg
| SLess
| SIfze of int
| SJump of int

byteCodes和revserse的函数可能如下所示:

let byteCode (l : sInstr list) : string = 
  let instrToString (bc : sInstr) =
    (match bc with 
    | SC    n -> [0; n]
    | SAdd    -> [1]
    | SSub    -> [2]
    | SMul    -> [3]
    | SNeg    -> [4]
    | SLess   -> [5]
    | SIfze n -> [6; n]
    | SJump n -> [7; n])

  String.Join(" ", (l |> List.map instrToString |> List.fold (fun acc lst -> acc @ lst) []))

let toInstr (bcString : string) : sInstr list = 
  let rec recToInstr bcList = 
    match bcList with
    | [] -> []
    | head :: tail -> 
        match head with
        | "0" -> SC(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
        | "1" -> SAdd :: recToInstr tail
        | "2" -> SSub :: recToInstr tail
        | "3" -> SMul :: recToInstr tail
        | "4" -> SNeg :: recToInstr tail
        | "5" -> SLess :: recToInstr tail
        | "6" -> SIfze(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
        | "7" -> SJump(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
        | _ -> []

  recToInstr (bcString.Split(' ') |> Array.toList)