0

I'm using STDIN.getch to get single characters from the console. I'd like to be able to interpret escaped characters such as \n in their raw form. I.e. If the user were to type \ followed by n I would like to combine them to represent the \n character not the \n string.

George
  • 903
  • 4
  • 19

2 Answers2

1

Tweak the method that processes your getch value to respond differently based on the character.

If the character is '\', then use getch again and set your user input variable to the equivalent escaped character.

If the character isn't '\' then process as you are already.

In terms of how to actually unescape the string you get from joining those two together, I got the following code options from https://stackoverflow.com/a/20131717/2585056

UNESCAPES = {
    'a' => "\x07", 'b' => "\x08", 't' => "\x09",
    'n' => "\x0a", 'v' => "\x0b", 'f' => "\x0c",
    'r' => "\x0d", 'e' => "\x1b", "\\\\" => "\x5c",
    "\"" => "\x22", "'" => "\x27"
}

def unescape(str)
  # Escape all the things
  str.gsub(/\\(?:([#{UNESCAPES.keys.join}])|u([\da-fA-F]{4}))|\\0?x([\da-fAF]{2})/) {
    if $1
      if $1 == '\\' then '\\' else UNESCAPES[$1] end
    elsif $2 # escape \u0000 unicode
      ["#$2".hex].pack('U*')
    elsif $3 # escape \0xff or \xff
      [$3].pack('H2')
    end
  }
end

That one is a bit complex but looks like it should work without being unsafe - some of the other options use eval, which would give users the ability to run any ruby statement they want :) If it's just for you, that might be ok - check the link above for other options.

Community
  • 1
  • 1
chrisdurheim
  • 406
  • 4
  • 6
  • That's fine, the question is more how to combine the `\ ` character and the `n` character into the single `\n` character. Rather than using a case statement to catch all possible combinations – George May 24 '15 at 18:20
  • @George thanks for clarifying the question. Updated my answer to cover how to unescape the character – chrisdurheim May 24 '15 at 20:52
  • Solution fails to find `\xHH` sequences where either `H` is captial `B`-`E` because it is missing a single hyphen, but StackOverflow won't let me submit an edit because it doesn't meet their minimum 6+ character edit threshold. – Ry Biesemeyer Feb 22 '19 at 18:46
1

Generally, you can just read a backslash and then try to read one of available escaped characters (more precisely, a second part of it). Then if you match appropriate character, return character what you need ("\n" in your case):

while(true) do
  char = STDIN.getch
  if char == "\\"
    puts "Type your espace character"
    s = STDIN.getch
    case s
      when 'n'
        puts 'New line typed'
        # but return "\n"
      when 'r'
        puts 'Carriage return typed'
        # but return "\r"
      when 't'
        puts 'Tabulation typed'
        # but return "\t"
      # ...
    end
  else
    puts "#{char} typed"
  end
end

Or you can concatenate characters you read and then replace with appropriate escaped sequence:

# assume s is a concatenated string
>> s = '123\n456'      #=> "123\\n456"
>> s.size              #=> 8
>> s.gsub!('\n', "\n") #=> "123\n456"
>> s.size              #=> 7
Vitalii Elenhaupt
  • 7,146
  • 3
  • 27
  • 43