解析传入的Ascii字符TCP流,处理退格字符

时间:2015-09-26 19:29:15

标签: f# ascii telnet

我需要解析来自套接字的输入流。 数据是从Telnet客户端发送的,因此我想通过查找流中的第一个'\r'字符来处理传入的字符串,然后在返回字符之前选择字节,最后处理任何backspace {{ 1}}字符。

在这里处理'\b'位的惯用方法是什么? 我目前正在使用一个可变堆栈并将chars推到它上面,如果有一个退格,我会弹出最后一个char。 然后将结果转换为字符串。

但我认为使用模式匹配和尾递归可能有一些很好的方法。 那么,怎样才能以F#方式完成呢?

'\b'

2 个答案:

答案 0 :(得分:12)

让我们首先将有问题的部分隔离到一个函数:

open System
open System.Collections.Generic

let handleBackspaces textToProcess : string =
    let stack = Stack<char>()
    for c in textToProcess do
        if c = '\b' then stack.Pop() |> ignore
        else stack.Push c
    stack |> Seq.rev |> Seq.toArray |> String

这有一个可变变量(stack)。只要有变量变量,就可以在递归函数中用累加器值替换它。这是一种方法:

open System

let handleBackspaces' textToProcess : string =
    let rec imp acc = function
        | [] -> acc
        | '\b'::cs -> imp (acc |> List.tail) cs
        | c::cs -> imp (c::acc) cs
    textToProcess |> Seq.toList |> imp [] |> List.rev |> List.toArray |> String

你会注意到我调用了acc的累加器值。 imp函数的类型为char list -> char list -> char list,它与传入的char list匹配:如果它为空,则返回累加器;如果它有'\b'作为头部,它会使用char从累加器中删除之前的List.tail;在所有其他情况下,它是第一个char到累加器并递归调用自身。

这是一个(希望令人满意的)FSI会议:

> handleBackspaces' "b\bfoo";;
val it : string = "foo"
> handleBackspaces' "foo";;
val it : string = "foo"
> handleBackspaces' "bar\bz";;
val it : string = "baz"
> handleBackspaces' "bar\b\boo";;
val it : string = "boo"
> handleBackspaces' "b\bfa\boo";;
val it : string = "foo"

一旦人们理解了如何将某事物建模为递归函数,就应该可以使用折叠来实现它,正如Ryan W Gough指出的那样。这是一种方法:

let handleBackspaces'' textToProcess : string =
    textToProcess
    |> Seq.fold (fun acc c -> if c = '\b' then acc |> List.tail else c::acc) []
    |> List.rev
    |> List.toArray
    |> String

答案 1 :(得分:1)

这样的感觉可以通过减少来完成吗?如果它不是退格,那么将字符构造给累加器,如果它只是将累加器设置为它的尾部?