задача
Читайте в возможно бесконечном текстовом потоке или файле, выводя его содержимое до hello
тех пор, пока не будет выведено слово , соблюдая следующие правила.
После
hello
вывода ваш код должен немедленно завершиться. Например, не следует ждать новой строки.Ваш код должен выводиться, как он идет. То есть он не должен читать огромное количество ввода, а затем начинать вывод.
Если поток / файл не содержит
hello
, ваш код должен просто выводить ввод навсегда или до тех пор, пока не будет достигнут конец потока / файла.Это чувствительный к регистру вызов, поэтому
hello
он не равенHello
.Вы можете предположить, что ввод состоит только из печатных символов ASCII и новых строк.
Ваш код не может ожидать, что текст будет завершен новой строкой или что во входных данных вообще будут какие-либо новые строки. Кроме того, ваш код не может предполагать, что он будет работать на машине с бесконечным объемом памяти.
Вы можете предположить, что ваш код будет вызываться из пустой директории.
Пример входного потока
I once had a horse called hellopina.
Выход
I once had a horse called hello
Чаевые
Запустите, yes | tr -d \\n | <your program>
чтобы проверить, работает ли он с бесконечными потоками. Если он ничего не печатает и / или не теряет память, программа не соответствует спецификации. Он должен печатать yyyyyyyyyyyyyyyyyyyyyy...
вечно без перевода строки.
Ответы:
Желе , 24 байта
Попробуйте онлайн!
Объяснение:
источник
C (gcc) ,
8180767572717069 байтПопробуйте онлайн!
Как это работает
Это полная программа. Мы определяем функцию f для наших целей. Чтобы сохранить байты, он объявляется с двумя аргументами, которые по умолчанию равны int . Это неопределенное поведение, но на практике n будет инициализироваться как 1 при запуске программы без дополнительных аргументов, c будет содержать младшие 32 бита указателя на вектор аргумента
Пока состояние
считает, что мы будем выполнять в то время как тело цикла в:
Чтобы полностью понять состояние, мы должны сначала изучить тело. Пока что мы наблюдаем только то, что
c=getchar()
считывает один байт из STDIN (если это возможно) и сохраняет его в переменной c .Последовательность байтов привет выглядит следующим образом в разных представлениях.
Все они попадают в диапазон [96, 192) , поэтому
c/96
оцениваются в 1 для каждого из этих байтов и в 0 для всех оставшихся символов ASCII. Таким образом,putchar(c)/96*c
( putchar печатает и возвращает свой аргумент) будет вычислено значение c, если c -`
это строчная буква, один из{|}~
символов или символ DEL; для всех остальных символов ASCII он будет равен 0 .Значение n обновляется путем смещения его на пять бит влево, а затем с помощью XOR результата с результатом предыдущего абзаца. Поскольку int имеет ширину 32 бита (или, как мы предполагаем в этом ответе), некоторые из сдвинутых битов могут «падать влево» (целочисленное переполнение со знаком является неопределенным поведением, но gcc ведет себя как инструкция x64, которую он генерирует здесь). Начиная с неизвестного значения n , обновив его для всех символов hello , мы получим следующий результат.
Обратите внимание, что младшие 25 битов образуют целое число 0xb33def , которое является магической константой в условии. Хотя между битами двух смежных байтов есть некоторое перекрытие, отображение байтов ниже 96 на 0 гарантирует, что нет никаких ложных срабатываний.
Условие состоит из двух частей:
~(getchar())
принимает побитовое НЕ результата чтения (или попытки чтения) байта из STDIN.Если getchar завершится успешно, он вернет значение прочитанного байта как int . Поскольку вход полностью состоит из символов ASCII, в считываемом байте могут быть установлены только его младшие 7 битов, поэтому в этом случае для побитового НЕ будут установлены его старшие 25 битов.
Если getchar терпит неудачу (больше нет ввода), он вернет -1, а побитовое НЕ будет 0 .
n-0xb33def<<7
вычитает магическую константу из n , а затем сдвигает результат на 7 единиц влево.Если последние 5 прочитанных байтов были привет , младшие 25 бит n будут равны 0xb33def, и вычитание обнулит их. Сдвиг разности даст 0, так как 7 старших битов «упадут влево».
С другой стороны, если последние 5 прочитанных байтов не были " привет" , будет установлен один из младших 25 битов разности; после сдвига будет один из старших 25 битов.
Наконец, если getchar был успешным, и мы еще не напечатали привет , будет установлен побитовый AND, все старшие 25 битов левого операнда и по крайней мере один из старших 25 битов правого операнда. Таким образом, вы
&
получите ненулевое целое число, и цикл продолжается.С другой стороны, если ввод исчерпан или мы уже напечатали привет , один из побитовых операндов И будет нулевым, и результат будет таким же. В этом случае мы вырываемся из цикла и программа завершается.
источник
Баш,
747510399888276 байт-10 байт благодаря @DigitalTrauma!
-11 байт благодаря @manatwork!
-6 байт благодаря @Dennis!
Объяснение:
Попробуйте онлайн!
источник
Лабиринт ,
4341 байтСпасибо Sp3000 за сохранение 2 байта.
Попробуйте онлайн!
объяснение
Основная идея состоит в том, чтобы закодировать последние пять символов в базе 256 в одно целое число. Когда появляется новый символ, мы можем «добавить» его, умножив целое число на 256 и добавив новую кодовую точку. Если мы хотим посмотреть только последние 5 символов, мы берем значение по модулю 256 5 = 2 40 = 1099511627776. Затем мы можем просто проверить, равно ли это значение 448378203247, что мы получаем, когда мы обрабатываем кодовые точки
hello
как основа - 256 цифр.Что касается кода ...
<...>
это немного лабиринт идиома. Это позволяет вам писать бесконечный цикл без какого-либо условного потока управления в одной строке, сохраняя много байтов на пробелах и переводах строк. Основное условие для того, чтобы это работало, это наличие двух одноразовых значений в верхней части стека, когда мы достигаем<
(мы обычно используем0
s для этого, но фактическое значение является произвольным).Конечно, программе нужна условная логика, чтобы понять, когда завершить работу. Но условно завершить программу можно путем деления на значение, равное нулю, когда мы хотим, чтобы программа закончилась. В
<...>
конструкт работает путем сдвига всю строку влево (циклически) , когда IP - находится на левом конце, а затем сразу же сдвигая его обратно в рабочее положение. Это означает, что код фактически выполняется справа налево. Давайте изменим это:Это одна итерация цикла, которая читает символ, завершается, если мы достигли EOF, печатает символ, добавляет его в нашу кодировку, усекает его до 5 символов, проверяет равенство
hello
и повторяет. Вот как это работает подробно (помните, что Labyrinth основан на стеке):источник
Brainfuck, 658 байт
Более 500 байтов находятся в константах, которые мне нужны для игры в гольф.
По сути, это конечный автомат, поэтому бесконечный ввод не является проблемой.
Это слегка прокомментированная версия
источник
ahehellob
правильной обработки случаев ; в середине потенциального совпадения он только проверяет следующую буквуhello
и не ищет началаh
для начала.Баш ,
736866 байтПредполагается каталог без или только скрытые файлы. Должен быть запущен как
<path/to/script>
.Попробуйте онлайн!
Как это работает (устарело)
В начале в то время цикла, мы первый тест , если строка в переменной s (изначально пустой) равна olleh ( привет назад, olé), и возвращает 0 (матч) или 1 (не совпадает) , соответственно. Хотя формально является частью условия цикла, результат не повлияет на него сам по себе, так как только последняя команда до этого
do
определяет, выполняется ли условие.Затем мы устанавливаем внутренний разделитель полей на пустую строку (чтобы
read
не задыхаться от пробелов), читаем raw bytes (-r
) из STDIN и сохраняем их вc
.$?
это код завершения предыдущей команды, поэтому он читает ровно один (-N1
) байт для несоответствия и нулевой bytes (-N0
). Чтение нулевых байтов, будь то из-за нажатия EOF или из-за того, что-N0
было указано, приводитread
к выходу с кодом состояния 1 , поэтому цикл while завершится; в противном случае тело выполняется, и мы начинаем заново.В теле мы сначала печатаем прочитанный байт, а затем обновляем его с помощью
s=$c${s::4}
. Это добавляет байт чтения к (до) первых четырех байтов в s , так что s будет равен olleh, как только будет напечатан hello .источник
мозговой трах, 117 байт
отформатирован:
Попробуйте онлайн .
Это инициализирует ленту с символами со
hello
смещением на107
, разнесенными по одному значению каждые три ячейки, затем отслеживает последние пять увиденных символов и проверяет совпадение с каждым новым обработанным символом, используя флаг справа от строки для отслеживать, был ли матч.источник
Рубин ,
4660 байтПопробуйте онлайн!
Читает символы из stdin до последних 5
hello
, затем выводит строку (или до тех пор, пока в stdin не останется символов). Завершается с ошибкой.Эквивалентно:
Или, более безликий
источник
a
растет каждый раз, когда читается символ Это сбой, если вход бесконечен?Python 3,
120116104 байтРаботает с бесконечными потоками, впервые в гольф, любые советы приветствуются.
Спасибо @DJMcMayhem за сохранение нескольких байтов :)
источник
c=[0,c+1]['hello'[c]==a]
должен сэкономить вам несколько байтов. Кроме того,a=1
короче тоже.while
в Python.Haskell,
414743 байтаЛень Хаскелла хорошо справляется с бесконечным вводом / выводом.
Попробуйте онлайн!
Редактировать: не обрабатывать конечный ввод - исправлено. Спасибо @Leo за указание.
Редактировать II: @ Орьян Йохансен сохранил 4 байта. Благодарность!
источник
|w@"hello"<-take 5l=w
.Cubix,
94 83 82 79 6356 байтExpanded:
Заметки
Попробуйте онлайн
Вы можете попробовать программу здесь .
объяснение
Главная идея
Общая идея заключается в том, что мы хотим прочитать символ, а затем проверить его на предмет изменяющихся символов (сначала
h
, затемe
, затемl
и т. Д.). Чтобы отслеживать пропущенного персонажа, мы держим его в самом низу стека. Когда нам это нужно, мы легко можем снова поднять его на вершину.Цикл чтения / записи
Цикл чтения-записи - это просто 5- я строка. Все неиспользуемые символы заменяются на no-ops (
.
):Это можно разделить на две части: чтение и (написание и проверка). Первая часть содержит инструкции вплоть до знака вопроса. Вторая часть - это остальная часть строки. Поскольку это зацикливается, мы предполагаем, что мы начинаем со стека
[...]
Вторая часть (написание и проверка) снова линейна. Стек начинается как
[next-char, ..., input]
. Мы абстрагировали следующий символ, потому что это меняется позже в программе.Теперь, IP начнется снова в начале этого цикла, сбрасывая следующий символ для проверки
h
.Соответствие следующему персонажу
Если IP сделал разворот (т. Е. Символ, который мы прочитали и напечатали, соответствовал следующему символу
'hello'
), нам нужно проверить, каким символом был ввод, и в зависимости от этого сдвинуть следующий символ в конец стека. После этого нам нужно вернуться к циклу чтения / записи, не помещаяh
его в стек, поэтому нам нужен другой способ попасть туда.Перво-наперво: определите, каким персонажем был ввод. Стек выглядит следующим образом :
[..., prev-char, input, 0]
.Чтобы сравнить ввод, мы
h
снова используем код символа . Первоначально это было потому, что я не знал, как я собираюсь с этим справиться, иh
это первый символ в строке, который нужно проверить, но в итоге это оказалось довольно удобным. Если мы вычтем код символа h из ввода, мы получим,-3
если вход естьe
,0
если вход естьh
,4
если входl
и7
если входo
.Это полезно, потому что
?
команда позволяет нам легко отделить отрицательные значения от положительных значений и нуля. Таким образом, если IP поворачивается влево, разница была отрицательной, поэтому ввод былe
, поэтому следующий символ должен бытьl
. Если IP продолжает идти прямо, разница была0
, поэтому ввод былh
, поэтому следующий символ должен бытьe
. Если вход являетсяl
илиo
, IP поворачивается направо.Все инструкции, выполненные до вышеупомянутого знака вопроса:
Теперь IP меняет свое направление, как описано выше. Давайте рассмотрим различные возможности.
вход
'e'
Сначала мы рассмотрим ввод
e
, который заставляет IP двигаться вверх от?
, так как разница равна 3. Все нерелевантные символы были удалены из куба.Символы выполняются в следующем порядке (исключая некоторые символы потока управления):
Теперь IP снова достиг цикла чтения / записи.
вход
'h'
Если вход был
'h'
, разница равна 0, поэтому IP не меняет своего направления. Снова куб, со всеми не относящимися к делу персонажами. Поскольку этот путь включает в себя довольно много неактивных операций, все пропущенные им операции были заменены&
. IP начинается с вопросительного знака.Выполненные инструкции:
И теперь мы снова входим в цикл чтения / записи, так что мы закончили.
Другие входы
Все остальные входные данные приводят к положительной разнице, поэтому IP-адрес поворачивается направо на вопросительный знак. Нам все еще нужно разделить
l
иo
то, что мы будем делать дальше.Разделение
'l'
и'o'
Имейте в виду, что разница составляет 7 для
o
и 4 дляl
и что мы должны завершить программу, если ввод былo
. Вот куб снова с нерелевантными частями, замененными на a,.
и нет-опы, кресты IP были заменены амперсандами.Различение между этими двумя
'l'
сИтак, теперь мы знаем, что вклад был
l
, но мы не знаем, какойl
. Если это первое, нам нужно подтолкнуть другогоl
к нижней части стека, но если это второе, нам нужно подтолкнутьo
. Помните, мы сохранили-3
в конец стека как раз перед тем, как выдвинуть первыйl
? Мы можем использовать это для разделения двух ветвей.Стек начинается как
[..., -3 or 140, ...]
Первый
'l'
Если это было первым
'l'
, нам нужно подтолкнуть другого'l'
. Для сохранения байтов мы используем те же символы, что и для первого'l'
. Мы можем упростить стек до[...]
. Вот соответствующая часть куба, где нет операций, замененных амперсандами.Следующие инструкции выполняются:
Мы собираемся войти в цикл чтения / записи, поэтому мы закончили с этой веткой.
второй
'l'
Если вход был вторым
'l'
в'hello'
, то IP повернул направо на знак вопроса. Еще раз, мы можем упростить стек,[...]
и IP начинается с, на?
этот раз, указывая на юг.Выполненные инструкции:
И IP собирается снова войти в цикл чтения / записи, так что мы закончили и с этой веткой.
источник
C ++,
142141 байтПопробуйте онлайн!
источник
#import
в программах GCC C ++ ...#import
- устаревшее расширение GCC.Узел, 124 байта
Не предполагая, что поток поместится в доступной памяти.
источник
C #, 134 байта
Попробуйте онлайн
Читает символ, проверяет, что это не -1 (EOS) и что мы еще не видели "привет", затем добавляет его в строку и записывает символ. Мы готовимся, потому что
s[0]
это намного короче(char)s
. Это имеет квадратичную стоимость в длине строки, так как он должен выделять и сканировать весь ввод каждый раз, когда он читает символ (это приведет к сбою после 2 Гбайт ввода из-за ограничений в CLR, это разрешено?)Для (длиннее: 142 байта) версии, которая не будет хватает памяти и которая имеет постоянную стоимость за символ, см. Ниже:
Последние хранят последние 5 символов в строке длиной 5, что означает короткие сравнения и дешевый поиск по последнему символу, но значительно дороже в обновлении.
источник
PHP,
57 5553 байтапоскольку нет бесконечных файлов, я беру ввод из STDIN. Беги с
-nr
.Циклический ввод, печать текущего символа, добавление к нему
$s
, сокращение$s
до последних 5 символов. Разорвать петлю, когда$s
естьhello
.источник
Vim, 39 байт
Попробуйте онлайн!
источник
PowerShell, 111 байт
Возможно, есть лучший способ сделать это, но я не могу видеть это в настоящее время.
Это читает нажатия клавиш, не подавляя эхо. Символ добавляется к $ x, который обрезается до последних 5 символов и сравнивается с "привет". Это продолжается до тех пор, пока сравнение не станет правдой.
Примечание: это не работает в PowerShell ISE. ReadKey отключен в этой среде.
источник
Схема 115 байтов
Читаемая версия:
Это берет отдельный символ из stdin каждый раз в цикле и отмечает его положение на целевом слове, когда оно встречает символы «привет».
Останавливается, когда ввод заканчивается или "привет" был замечен. Нет памяти, используемой в бесконечном потоке.
источник
AWK, 95 байт
Здесь я узнал 2 вещи:
1) Чтобы разделить записи между символами, нужно использовать,
RS="(.)"
а затемRT
использовать вместо$1
2)
ORS
используетсяprint
и по умолчанию равен"\n"
3) я не могу сосчитать до 2, а использование
printf
"дешевле", чем назначениеORS
и с помощьюprint
Пример использования: поместите код в файл
или
Код был протестирован по
yes | ...
предложению Денниса, и я видел много-многоy
s.К вашему сведению, вы можете сделать присвоение RS в качестве опции и вытащить его из
BEGIN
блока через:источник
BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}
.Python 3 (Linux),
7372 байтаСпасибо @MitchSchwartz за отыгрывание 1 байта!
Попробуйте онлайн!
источник
while
правильно оценить состояние? Похоже, вы сравниваете логическое значение с пустой строкой.s[print(end=c):4]
сохраняет байт'olleh'!=s and s>''and''<c)
. Средний тест не нужен, но их цепочка короче, чем простая'olleh'!=s and''<c
.8086 машинный код, 22 байта
Эквивалентный код сборки:
источник
Pyth,
4947 байтПиф не очень хорош для ввода одного символа ввода. Все
$__import__("sys").stdin.read(1)
просто делает это. Кроме того, это означает, что это работает только в автономном режиме.Все остальное коротко ...
Программа представляет собой цикл без тела. Внутри условия программа читает символ, печатает его обратно, добавляет этот символ
k
(который изначально является пустой строкой), обрезает все, кроме последних 5 символовk
, и затем проверяет, что результат не соответствует"hello"
.32 символа получают один байт ввода, 15 символов делают все остальное.
Проверено на Linux, работает даже без перевода строки, бесконечного ввода и т. Д.
источник
Луа,
6864 байтаисточник
l:sub(-4)
, тогда вы можете уменьшить инициализациюl=""
.Рубин,
59494843 байтаТеперь без крыс, короче и без утечки памяти.
Благодаря Деннису удалось сэкономить 5 байтов, избавившись от скобок и пробела
источник
Рёда ,
4947 байтПопробуйте онлайн!
Это анонимная функция, которая читает символы из своего входного потока и выводит их до тех пор, пока не будет найдено «привет». Он использует массив
a
для отслеживания последних символов.Он выводит некоторый мусор в STDERR, но я понял, что это разрешено .
Объяснение:
источник
Java 7,
122118124123150141 байтТеперь останавливается, когда достигнут конец потока. Теперь обрабатывает бесконечный ввод без исчерпания памяти.
источник
write
чтобы его использовали вместоprint
. Я не могу отменить свое понижение, извините за это :(Рубин, 51 байт
источник
AHK , 116 байт
Там нет ничего умного или волшебного. Переменная
%1%
является первым переданным аргументом и должна быть путем к файлу с потоком. Файл должен быть сохранен при обновлении, но код будет считан до конца, даже если он расширится после начала чтения.источник
Mathematica, 107 байт
Вывод становится полем, в котором пользователь может бесконечно набирать текст (включая новые строки), пока последние 5 символов не будут равны
"hello"
; в этот момент он выходит.источник
брейкфук , 281 байт
Я не уверен почему, но я просто чувствовал, что мозговитость была правильной вещью, чтобы сделать это. Не требует бесконечной памяти и может выводить вечно.
Разъяснения
Попробуйте онлайн!
источник
ahehellob
.