Странное поведение при изменении разделителя строк, а затем обратном его изменении

При попытке для чтения многострочного ввода из командной строки:

# change line separator
$/ = 'END'
answer = gets
pp answer

Однако я получаю странное поведение от STDIN#gets, когда пытаюсь изменить $/ обратно:

# put it back to normal
$/ = "\n"
answer = gets
pp answer
pp 'magic'

Это приводит к такому выводу при выполнении с Ruby:

$ ruby multiline_input_test.rb
this is
        a multiline
  awesome input string
                        FTW!!
END
"this is\n\ta multiline\n  awesome input string\n            \t\tFTW!!\t\nEND"
"\n"
"magic"

(Я ввожу до END, а остальное выводится программой, затем программа завершает работу.)

Он не останавливается, чтобы получить ввод от пользователя после того, как я изменю $/ обратно на "\n". Итак, мой вопрос прост: почему?

В рамках более крупного (но все же небольшого) приложения я пытаюсь разработать способ записи заметок; как бы то ни было, это странное поведение потенциально разрушительно, так как остальная часть моей программы не сможет работать должным образом, если я не смогу сбросить разделитель строк. Я пробовал все способы использования двойных и одинарных кавычек, но, похоже, это не проблема. Любые идеи?


person Daniel Brady    schedule 05.07.2013    source источник
comment
Ваше описание в последнем блоке кода непонятно. Какая часть является кодом, какая часть является пользовательским вводом, а какая частью является ответом?   -  person sawa    schedule 05.07.2013
comment
@sawa Прости за это. Фрагменты кода, которые я предоставил, — это весь код, который я выполняю в «multiline_input_test.rb». Когда это выполняется, он приостанавливается, ожидая ввода пользователя. Я ввел это многострочную потрясающую входную строку FTW!! (со случайным пробелом), затем набрал «КОНЕЦ». Остальное то, что было распечатано: никакой другой паузы при выполнении второго gets из моего кода.   -  person Daniel Brady    schedule 05.07.2013
comment
похоже, что второй gets просто возвращает новую строку, которую я никогда не вводил   -  person Daniel Brady    schedule 05.07.2013


Ответы (1)


Проблема, с которой вы столкнулись, заключается в том, что ваш ввод заканчивается на END\n. Ruby видит END, а в буфере еще осталось \n. Вы действительно успешно установили разделитель входных записей обратно на \n, так что этот символ сразу же используется вторым gets.

Таким образом, у вас есть два простых варианта:

  1. Установите разделитель входных записей на END\n (используйте двойные кавычки, чтобы работал символ новой строки):

    $/ = "END\n"
    
  2. Очистите буфер дополнительным вызовом gets:

    $/ = 'END'
    answer = gets
    gets # Consume extra `\n`
    

Я считаю вариант 1 более понятным.

Это показывает, что он работает в моей системе, используя вариант 1:

$ ruby multiline_input_test.rb 
this is
        a multiline
  awesome input string
                        FTW!!
END
"this is\n        a multiline\n  awesome input string\n                        FTW!!\nEND\n"
test
"test\n"
"magic"
person Darshan Rivka Whittle    schedule 05.07.2013
comment
Аааа, спасибо! Я считаю, что вы сэкономили мне много минут отладки. Это имеет смысл, я уже думал что-то вроде очистки буфера, но мне тоже нравится ваш первый вариант как лучшая альтернатива. - person Daniel Brady; 05.07.2013
comment
Кстати, спасибо за правки моего вопроса :) ясность всегда важна. - person Daniel Brady; 05.07.2013