Parse TCP input stream in Ascii char s, backspace for char descriptor

I need to parse input streams from a socket. Data is sent from the Telnet client, and so I want to process incoming lines by searching for the first character '\r' in the stream, then select bytes before returning char and finally process any backspace characters '\b' .

What would be the idiomatic way of dealing with the '\b' bits here? I am currently using a mutable stack and pushing characters on it, and if there is a return space, I output the last char. Then just turn the result into a string.

But I believe that there is probably a good way to do this using pattern matching and tail recursion. So how can this be done in F # way?

 let receiveInput (inputBuffer:StringBuilder) (received:Tcp.Received)= let text = Encoding.ASCII.GetString(received.Data.ToArray()); inputBuffer.Append(text) |> ignore let all = inputBuffer.ToString() match all.IndexOf('\r') with | enter when enter >= 0 -> let textToProcess = all.Substring(0,enter) inputBuffer.Remove(0,enter+2) |> ignore //this is the part I'm wondering about let stack = new Stack<char>() for c in textToProcess do if c = '\b' then stack.Pop() |> ignore else stack.Push c let input = new System.String(stack |> Seq.rev |> Seq.toArray) Some(input) | _ -> None 
+7
f # ascii telnet
source share
2 answers

Let the allocation of the problematic part of the function begin:

 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 

This has one mutable variable ( stack ). Whenever you have a variable, you can replace it with the battery value in a recursive function. Here is one way to do this:

 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 

You will notice that I named the battery value for acc . The imp function is of type char list -> char list -> char list , and it corresponds to the incoming char list : if it is empty, it returns the drive; if it has '\b' as the head, it removes the previous char from the battery using List.tail ; and in all other cases, it transfers the first char to the battery and calls itself recursively.

Here's a (hopefully satisfactory) FSI session:

 > 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" 

Once someone understands how to model something as a recursive function, it should be possible to implement it using a fold instead, as Ryan U Gough points out. Here is one way to do this:

 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 
+11
source share

Feels like this can be done with a decrease? Does the symbol skip to the battery if it is not inverse space, if it simply places the battery in the tail?

+1
source share

All Articles