Ви мали мене привіт


30

Завдання

Читайте, можливо, нескінченний текстовий потік або файл, виводячи його вміст до виведення слова 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...назавжди без нових рядків.


1
Чи дозволяється нам читати що-небудь після "привіт"? Здається, питання забороняє будь-яке додаткове читання, яке може бути проблематичним на таких мовах, як (Стандартна) C, які забезпечують введення в буферизований режим із автоматичним читанням вперед.
Toby Speight

Напевно, ви повинні змінити прийняту відповідь на збірку, оскільки вона на 2 байти коротша.
Rɪᴋᴇʀ

@Riker Було б чудово, якби хтось міг це перевірити або хоча б сказати, що вони вважають, що це працює спочатку.

Відповіді:


2

Желе , 24 байти

“Ṣẉ»ẇ⁸Ṇȧ®
ṫ-3;ƈ©Ȯ¤µ⁺Ç¿ṛ“

Спробуйте в Інтернеті!

Пояснення:

ṫ-3;ƈ©Ȯ¤µ⁺Ç¿ṛ“ Main link. Arguments: 0
ṫ-3            Truncate the list to its 4 last elements.
   ;ƈ©Ȯ¤       Store a character from STDIN in the register, print it, and append it to the list (list is initially [0]).
        µ      Start a new monadic chain, everything to the left is a link.
          Ç    Execute the helper link with the existing list as its argument.
         ⁺ ¿   Do-while loop, left link is body, right link is condition.
            ṛ“ When the loop ends, replace the return value with [] (invisible on output).

“Ṣẉ»ẇ⁸Ṇȧ® Helper link. Arguments: string
“Ṣẉ»ẉ⁸Ṇ   Check if "hello" isn't in the string.
        ® Return the character we stored in the register.
       ȧ  Check if both of the above are truthy.

26

C (gcc) , 81 80 76 75 72 71 70 69 байт

main(n,c){while(~(c=getchar())&n-0xb33def<<7)n=n<<5^putchar(c)/96*c;}

Спробуйте в Інтернеті!

Як це працює

Це повна програма. Ми визначаємо функцію f для наших цілей. Для збереження байтів він оголошується двома аргументами, за замовчуванням до int . Це невизначена поведінка, але на практиці n буде ініціалізовано як 1 при запуску програми без додаткових аргументів, c утримує нижні 32 біти вказівника на вектор аргументу

Поки стан

~(c=getchar())&n-0xb33def<<7

вважає, що ми будемо виконувати в той час як тіло циклу в:

n=n<<5^putchar(c)/96*c

Щоб повністю зрозуміти стан, ми повинні спочатку оглянути організм. На даний момент все, що ми спостерігаємо, - це те, що c=getchar()читає один байт зі STDIN (якщо можливо) і зберігає його у змінній c .

Привіт послідовності байтів виглядає наступним чином у різних поданнях.

char     decimal     binary (8 bits)
'h'      104         0 1 1 0 1 0 0 0
'e'      101         0 1 1 0 0 1 0 1
'l'      108         0 1 1 0 1 1 0 0
'l'      108         0 1 1 0 1 1 0 0
'o'      111         0 1 1 0 1 1 1 1

Усі вони потрапляють у діапазон [96, 192) , тому c/96оцінюватимуть до 1 для кожного з цих байтів та до 0 для всіх символів, що залишилися ASCII. Таким чином, putchar(c)/96*c( putchar друкує та повертає свій аргумент) буде оцінено до c, якщо c є `, малі літери, один {|}~або символ DEL; для всіх інших символів ASCII він оцінить до 0 .

n оновлюється, переміщуючи його на п’ять біт ліворуч, потім XORing результат з результатом з попереднього абзацу. Оскільки int має 32 біти в ширину (або так ми припускаємо в цій відповіді), деякі зміщені біти можуть "впасти ліворуч" (переливання підписаного цілого числа є невизначеним поведінкою, але gcc поводиться як інструкція x64, яку він генерує тут). Починаючи з невідомого значення n , оновивши його для всіх символів привіт , ми отримуємо наступний результат.

 n  ?????????????????????????|???????
'h'                          |    01101000
'e'                          |         01100101
'l'                          |              01101100
'l'                          |                   01101100
'o'                          |                        01101111
-----------------------------+--------------------------------
    <------ discarded ------>|???????0101100110011110111101111

Зауважимо, що нижні 25 біт утворюють ціле число 0xb33def , яке є магічною константою в умові. Хоча між бітами двох сусідніх байтів є деяке перекриття, відображення байтів нижче 96 до 0 гарантує відсутність помилкових позитивних результатів.

Умова складається з двох частин:

  • ~(getchar()) приймає побітові НЕ результату читання (або спроби читання) байта від STDIN.

    Якщо getchar вдався, він поверне значення прочитаного байта як int . Оскільки вхід повністю складається з символів ASCII, байт зчитування може мати лише 7 нижчих бітів, тому побітовий НЕ матиме найвищі 25 біт у цьому випадку.

    Якщо getchar вийде з ладу (більше немає введення), він повернеться -1 і побітовий NOT буде 0 .

  • n-0xb33def<<7віднімає магічну константу від раніше від n , а потім зміщує результат 7 одиниць вліво.

    Якщо останні 5 прочитаних байтів були привіт , найнижчі 25 біт n будуть дорівнювати 0xb33def, і віднімання зведе їх на нуль. Зсув різниці призведе до 0 оскільки 7 найвищих біт "впадуть зліва".

    З іншого боку, якщо останні 5 прочитаних байтів не привіт , буде встановлено один з найнижчих 25 біт різниці; після зсуву буде один з найвищих 25 біт.

Нарешті, якщо getchar був успішним, і ми не надрукували привіт , встановлено побіт І, всі найвищі 25 біт лівого операнда та принаймні один із найвищих 25 біт правого. Таким чином, &вийде ненульове ціле число, і цикл продовжується.

З іншого боку, якщо вхід вичерпано або ми вже надрукували привіт , один з операндів бітового AND буде нульовим, і таким чином буде результат. У цьому випадку ми вириваємося з циклу і програма припиняється.


Вам, мабуть, варто було б зазначити, що це залежить від коду, який кодується в ASCII, перш ніж заглиблюватися в пояснення.
Toby Speight

2
@TobySpeight Я не думаю, що це вказувати звичайно. Який тип несумісного кодування ASCII очікує на використання відповіді C?
Денніс

EBCDIC - це очевидне кодування, яке не є ASCII. C не призначає конкретного кодування символів (лише те, що десяткові цифри повинні бути представлені послідовними значеннями в порядку).
Toby Speight

вищевказана програма зупиняється, якщо потік містить рядок не ascii "« úá ÷ o "1: o 111 6f 2: ÷ 246 f6 3: 160 160 a0 4: ú 163 5:« 174
RosLuP

@RosLuP Технічний виклик гарантує, що вхід буде складатися з друкованих символів ASCII та нових рядків.
Денніс

19

Баш, 74 75 103 99 88 82 76 байт

-10 байт завдяки @DigitalTrauma!
-11 байт завдяки @manatwork!
-6 байт завдяки @Dennis!

IFS=
b=ppcg
while [ ${b/hello} ];do
read -rN1 a
b=${b: -4}$a
echo -n $a
done

Пояснення:

IFS=    # making sure we can read whitespace properly
b=ppcg  # set the variable b to some arbitrary 4 letter string

while [ ${b/hello} ]; do  # while the variable b doesn't contain "hello", do the following
    read -rN1 a           # get input
    b=${b: -4}$a          # set b to its last 4 chars + the inputted char
    echo -n $a            # output the inputted char
done

Спробуйте в Інтернеті!


2
Це чудово! Я сподівався, що буде хитра відповідь.

13

Лабіринт , 43 41 байт

Завдяки Sp3000 за збереження 2 байт.

<_%-742302873844_::%*:*:420#+.:%):,*652_>

Спробуйте в Інтернеті!

Пояснення

Основна ідея полягає в кодуванні останніх п’яти символів в базовій області 256 в єдине ціле число. Коли з'явиться новий символ, ми можемо "додати" його, помноживши ціле число на 256 і додавши нову кодову точку. Якщо ми хочемо подивитися лише на останні 5 символів, ми беремо значення модуля 256 5 = 2 40 = 1099511627776. Тоді ми можемо просто перевірити, чи дорівнює це значення 448378203247, що ми отримуємо, коли обробляємо кодові точки helloяк база-256 цифр.

Щодо коду ... <...>це трохи ідіома Лабіринту. Це дозволяє записувати нескінченний цикл без будь-якого умовного потоку управління в одному рядку, економлячи багато байтів на пробілах та стрічкових каналах. Основна умова для цього - це два одноразових значення на вершині стека, коли ми доходимо до <(ми зазвичай 0для цього використовуємо s, але фактичне значення є довільним).

Звичайно, програмі потрібна певна умовна логіка, щоб визначити, коли потрібно припинити. Але умовно закінчити програму можливо шляхом ділення на значення, яке дорівнює нулю, коли ми хочемо, щоб програма закінчилася. У <...>конструкт працює шляхом зсуву весь рядок вліво (циклічно) , коли IP - знаходиться на лівому кінці, а потім відразу ж зрушуючи його назад в робоче положення. Це означає, що код фактично виконується праворуч ліворуч. Звернемо це:

_256*,:)%:.+#024:*:*%::_448378203247-%_

Це одна ітерація циклу, яка читає символ, закінчується, якщо ми дійшли до EOF, друкує персонаж, додає його до кодування, обрізає, що до 5 символів, перевіряє рівність helloі повторює. Ось як це детально працює (пам’ятайте, що Лабіринт базується на стеках):

_256*            Multiply the encoding by 256 in preparation for the next iteration.
,                Read one byte from STDIN.
:)%              Duplicate, increment, modulo. If we hit EOF, then , returns
                 -1, so incrementing and modulo terminates the program due to
                 the attempted division by zero. However, if we did read a
                 character, we've just compute n % (n+1), which is always n itself.
:.               Print a copy of the character we just read.
+                Add it to our encoding (we'll make sure to multiply the
                 encoding by 256 at the end of the iteration, so there's room
                 for our new character).
#024             Push 1024, using the stack depth to push the initial 1.
:*:*             Square it twice. That gives 2^40.
%                Take the encoding modulo 2^40 to truncate it to the last 5
                 characters.
::               Make two copies of the encoding.
_448378203247    Push the value that corresponds to "hello".
-                Subtract it from the encoding, giving zero iff the last 5
                 characters were "hello".
%                Take the other copy of the encoding modulo this value, again
                 terminating if we've reached "hello".
                 The actual value of this modulo - if it didn't terminate the
                 the program - is junk, but we don't really care, we just need
                 any disposable value here for the <...>
_                We push a zero as the second disposable value.

8

Brainfuck, 658 байт

+[>,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<,.>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[-<->]+<[>-<[-]]>[-<<->>]]]]]<<]

Понад 500 байт знаходиться в константах, які мені потрібно трохи пограти в гольф.

По суті це державна машина, тому нескінченне введення не є проблемою.

Це трохи коментована версія

+
[
  >,.
  >h
  [-<->]
  +<
  [
    >-<[-][in input spot, not h]
  ]
  >
  [
    -
    <
    [in input spot, h has been read]
    ,.
    >e
    [-<->]
    +<
    [
      >-<[-][in input spot, not e]
    ]
    >
    [
      -
      <
      [in input spot, e has been read]
      ,.
      >l
      [-<->]
      +<
      [
        >-<[-][in input spot, not l]
      ]
      >
      [
        -
        <
        [in input spot, l has been read]
        ,.
        >l
        [-<->]
        +<
        [
          >-<[-][in input spot, not l]
        ]
        >
        [
          -
          <
          [in input spot, l has been read]
          ,.
          >o
          [-<->]
          +<
          [
            >-<[-][in input spot, not o]
          ]
          >
          [
            -
            <
            [in input spot, o has been read]
            <->>
          ]
        ]
      ]
    ]
  ]
  <<
]

Це виглядає весело :)

Ласкаво просимо до головоломки програмування та коду для гольфу StackExchange!
betseg

1
Цей код має декілька проблем, але найбільша проблема полягає в тому, що він не включає логіку для обробки справ, як ahehellobправильно; в середині потенційного матчу він перевіряє лише наступну букву в helloі не шукає, hщоб почати спочатку.
Мітч Шварц

8

Баш , 73 68 66 байт

IFS=
[[ $1 != olleh ]]&&read -rN1 c&&echo -n $c&&exec $0 $c${1::4}

Передбачає каталог з відсутніми або лише прихованими файлами. Повинно працювати як <path/to/script>.

Спробуйте в Інтернеті!

Як це працює (застаріло)

На початку в той час циклу, ми перший тест , якщо рядок в змінної s (спочатку порожній) дорівнює olleh ( привіт назад, olé), і повертає 0 (матч) або 1 (не збігається) , відповідно. Хоча формально є частиною умови циклу, результат не вплине на нього самостійно, оскільки лише остання команда перед цим doвизначає, чи виконується умова.

Далі ми встановлюємо внутрішній роздільник поля на порожній рядок (так що readне задушиться у пробілі), читаємо необроблені байти ( -r) від STDIN і зберігаємо їх у c. $?є вихідним кодом попередньої команди, тому зчитується рівно один ( -N1) байт для невідповідності та нульових байтів ( -N0). Читання нульових байтів, незалежно від того, чи було це в результаті попадання на EOF або тому, що -N0було вказано, викликає readвихід із кодом статусу 1 , тому цикл while закінчиться; інакше тіло виконується і ми починаємо спочатку.

У тілі, ми спочатку надрукувати байти ми читаємо, то оновлення S з s=$c${s::4}. Це передбачає, що прочитаний байт до (до) перших чотирьох байтів у s , тож s буде дорівнює olleh, як тільки надрукується привіт .


Дуже приємно насправді!

8

мозковий ебать, 117 байт

--->>>------>>>+>>>+>>>++++<,[.-----<-[>--<-----]<[<<<]>>>[<[<<<+>>>>->+<<-]>[>>
+>]<[+[-<<<]]>>[<+>-]>>]<[[-]<<<,<]>]

Відформатовано:

--->>>------>>>+>>>+>>>++++
<,
[
  .-----<-[>--<-----]<[<<<]
  >>>
  [
    <[<<<+>>> >->+<<-]
    >[>>+>]
    <[+[-<<<]]
    >>[<+>-]
    >>
  ]
  <[[-]<<<,<]
  >
]

Спробуйте в Інтернеті .

При цьому ініціалізується стрічка з символами, helloзміщеними на 107, розміщеними з одним значенням кожні три комірки, а потім слідкує за останніми п’ятьма символами, які бачили, і перевіряє відповідність кожному новому символу, що обробляється, використовуючи прапор праворуч від рядка для слідкуйте за тим, чи відбувся збіг.


7

Рубі , 46 60 байт

a="";loop{q=$<.getc;~p if a[-5..-1]=="hello"||!q;a+=q;$><<q}

Спробуйте в Інтернеті!

Читає символи від stdin до останніх 5 hello, потім виводить рядок (або поки в stdin не залишиться жодних символів). Припиняється помилкою.

Дорівнює:

a = ""
loop {
    q = $<.getc
    ~p if a[-5..-1] == "hello" || !q
    a += q
    $><< q
}

Або, ще неозоріші:

a = ""
loop do
    q = STDIN.getc
    break if a[-5..-1] == "hello" or not q
    a += q
    print q
end

1
aзростає щоразу, коли читається чар. Це збої, якщо вхід нескінченний?
betseg

@betseg хм, можливо. Дозвольте мені побачити, чи можу я це виправити
Conor O'Brien

7

Пітон 3, 120 116 104 байт

Працює з нескінченними потоками, вперше гольфу, будь-які поради цінуються.

import sys
a=1
c=''
while(a):
    a=sys.stdin.read(1)
    if a:print(end=a)
    c=(c+a)[-5:]
    if c=='hello':break

Дякую @DJMcMayhem за збереження деяких байтів :)


Ласкаво просимо на сайт! c=[0,c+1]['hello'[c]==a]має заощадити кілька байтів. Також a=1коротше теж.
DJMcMayhem

2
Не потрібні дужки whileв Python.
PurkkaKoodari

6

Haskell, 41 47 43 байт

f l|w@"hello"<-take 5l=w|a:b<-l=a:f b|1<2=l

Лінь Haskell добре справляється з нескінченним входом / виходом.

Спробуйте в Інтернеті!

Редагувати: не оброблялось кінцеве введення - фіксовано. Дякую @Leo за вказівку.

Правка II: @ Ørjan Johansen зберег 4 байти. Спасибі!


2
Введення також може бути кінцевим, тому я думаю, що вам потрібно розібратися з випадком, коли ви досягнете кінця рядка
Лев

@Leo: На жаль, це зовсім пропустили. Виправлено.
німі

2
Перший охоронець можна скоротити до |w@"hello"<-take 5l=w.
Ørjan Johansen

@ ØrjanJohansen: о, це приємно. Спасибі!
німі

6

Cubix, 94 83 82 79 63 56 байт

p>q'-?w.uh'e@U7.'hqi?oqB-!ul.-..$WWu_q<o'\;>....6t?.../!@

Розширено:

        p > q '
        - ? w .
        u h ' e
        @ U 7 .
' h q i ? o q B - ! u l . - . .
$ W W u _ q < o ' \ ; > . . . .
6 t ? . . . / ! @ . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Примітки

  • Інтерпретатор вимикає поле введення при запуску програми. Таким чином, нескінченний потік введення неможливий. Ця програма приймає вхідний символ за символом, тож якби не обмеження, воно працювало б належним чином.
  • Ця програма не очищає стек, і вона стає брудною дуже швидко. Оскільки машина, на якій буде використовуватися, очевидно, може давати нескінченні вхідні потоки, здається розумним припустити, що вона також має нескінченну пам'ять.
  • Будь-яка допомога в гольфі дуже цінується.

Спробуйте в Інтернеті

Ви можете спробувати програму тут .

Пояснення

Загальна ідея

Загальна ідея полягає в тому, що ми хочемо прочитати персонаж, а потім перевірити його щодо різних символів (спочатку h, потім e, потім lтощо). Щоб відслідковувати персонаж, який ми пропустили, ми зберігаємо його в самому низу стека. Коли нам це потрібно, ми можемо легко знову піднести його до вершини.

Читання / запис циклу

Цикл читання-запису - це просто 5- й рядок. Усі символи, які не використовуються, замінюються no-ops ( .):

        . . . .
        . . . .
        . . . .
        @ . . .
' h q i ? o q B - ! u l . - . .
. . . . _ . . . . . . . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Це можна розділити на дві частини: читання та (написання та перевірка). Перша частина містить вказівки до питання про питання, включаючи знак питання. Друга частина вгору - решта рядка. Оскільки ця петля навколо, ми припускаємо, що ми починаємо з стека[...]

    @
'hqi?
    _

Explanation
'h          Push the character code of the h
            Stack: [..., 104]
  q         Send it to the bottom
            Stack: [104, ...]
   i        Read one character of the input (-1 for EOF)
            Stack: [104, ..., input]
    ?       Start of condition:
              if (input < 0):
    @           execute '@', ending the program
              if (input = 0):
                continue going right
              if (input > 0):
    _           turn to the right, reflect back ('_') and
                turn right again, effectively not changing 
                the direction at all

Друга частина (написання та перевірка) знову лінійна. Стек починається як [next-char, ..., input]. Ми абстрагували наступного символу, оскільки це змінюється пізніше в програмі.

oqB-!ul.-  Explanation
o          Output the character at the top of the stack
 q         Send the input to the bottom of the stack
           Stack: [input, next-char, ...]
  B        Reverse the stack
           Stack: [..., next-char, input]
   -       Push the difference of the top two characters, which
           is 0 if both are equal, something else otherwise
           Stack: [..., next-char, input, diff]
    !      if (diff = 0):
     u       make a u-turn to the right
           else:
      l.     execute two no-ops
        -    push [input - next-char - input], which is disregarded
             later, so it effectively is a no-op as well.

Тепер на початку цього циклу знову розпочнеться IP, скидаючи наступний символ для перевірки h.

Відповідність наступного символу

Якщо IP зробив поворот (тобто символ, який ми читали та друкували, збігався з наступним символом 'hello'), нам потрібно перевірити, який саме символ був введеним, і залежно від цього натисніть наступний символ в нижній частині стека. Після цього нам потрібно повернутися до циклу читання / запису, не натискаючи hна стек, тому нам потрібен інший спосіб дістатися туди.

Спочатку все: визначте, який символ був вхідним. Стек виглядає наступним чином : [..., prev-char, input, 0].

        . . . .
        - ? . .
        u h ' e
        . . . .
. . . . . . . . . ! u . . . . .
. . . . . . . . . \ ; . . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Для порівняння введення ми знову використовуємо код символу h. Спочатку це було тому, що я насправді не знав, як я збираюся це впоратися, і hє першим символом у рядку, на який потрібно перевірити, але в кінцевому підсумку це було досить зручно. Якщо відняти код символу h від входу, ми отримаємо, -3якщо вхід є e, 0якщо вхід є h, 4якщо вхід є lі 7якщо вхід є o.

Це корисно, оскільки ?команда дозволяє нам легко відокремити від’ємні значення від позитивних та нульових. Таким чином, якщо IP повертає ліворуч, різниця була негативною, тому введення було e, тому наступним символом має бути an l. Якщо IP продовжує йти прямо, різниця була 0, тому введення було h, тому наступним символом має бути an e. Якщо вхід є lабо o, IP-адреса повертається праворуч.

Всі вказівки, виконані перед згаданим знаком питання:

;!e'h-     Explanation
;          Delete the top of the stack
           Stack: [..., prev-char, input]
 !         if (input = 0):
  e          execute 'e' (no-op)
   'h      Push the character code of h
           Stack: [..., prev-char, input, 104]
     -     Push the difference of the input and 104
           Stack: [..., prev-char, input, 104, diff]

Тепер ІС змінює свій напрямок, як детально описано вище. Перейдемо до різних можливостей.

Вхідні дані 'e'

Спочатку ми розглянемо вхідний сигнал e, який змушує IP переміщуватися вгору від ?, оскільки різниця становить 3. Всі невідповідні символи були вилучені з куба.

        . > q '
        . ? . .
        . . . .
        . . . .
. . q . . . . . . . . l . . . .
$ W W . . . . . . . . > . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Символи виконуються в такому порядку (виключаючи деякі символи потоку управління):

q'l$WWq
q           Save the difference (-3) to the bottom of the stack so
            we can tell whether the l on the bottom of the stack is
            the first or the second l in hello
            Stack: [-3, ...]
 'l         Push the character code of l to the stack
            Stack: [-3, ..., 108]
   $W       no-op
     W      Sidestep into the loop
      q     Send the character code to the bottom
            Stack: [108, -3, ...]

Тепер IP знову дійшов до циклу читання / запису.

Вхідні дані 'h'

Якщо вхід був 'h', різниця дорівнює 0, тому IP не змінює свого напрямку. Ось знову куб, з нею видалені всі неактуальні символи. Оскільки цей шлях включає в себе досить багато відсутніх вікон, всі параметри, які він проходить, були замінені на &. IP починається з знака питання.

        . . . .
        . ? w .
        . . ' e
        . . . .
. . . . . . . . . ! . . . . . .
. . . u _ q < . . \ . . . . . .
. . ? & & & / . . & . . . . . .
. . & . . . . . . & . . . . . .
        . . . .
        & & & &
        . . . .
        . . . .

Виконані інструкції:

'e!\?q_
'e          Push the character code of the e
            Stack: [..., 101]
  !         if (101 = 0):
   \          reflect away (effectively a no-op)
    ?       if (101 > 0):
              turn right (always happens)
     q      Move 101 to the bottom of the stack
            Stack: [101, ...]
      _     No-op

А тепер ми знову входимо в цикл читання / запису, тому ми закінчили.

Інші входи

Усі інші входи призводять до позитивної різниці, тому IP-знак повертається праворуч на знак питання. Нам ще потрібно відокремити lта o, так що ми зробимо далі.

Відокремлення 'l'та'o'

Майте на увазі, що різниця становить 7 за oі 4 для, lі що ми повинні закінчити програму, якщо введення було an o. Ось куб знову з невідповідними частинами, заміненими на .а, без опор, IP-хрестики були замінені на амперсанди.

        . . q .
        . ? w .
        . h ' .
        . U 7 .
. . . . . . . . . . . . . - . .
. . . . . . . . . . . . . & . .
. . . . . . / ! @ . . . . & . .
. . . . . . & . . . . . . & . .
        . . & .
        . . & .
        . . & .
        . . & .

h7'wq-!@    
h           no-op
 7          Push 7 to the stack
            Stack: [..., diff, 7]
  'wq       Push w to the stack and send it to
            the bottom. We don't care about it,
            so it's now part of the ellipsis.
            Stack: [..., diff, 7]
     -!     if (diff = 7):
       @        End the program

Розрізнення між двома 'l'с

Отже, тепер ми знаємо, що вхід був l, але ми не знаємо, який l. Якщо це перше, нам потрібно просунути інше lдо нижньої частини стека, але якщо це друге, нам потрібно натиснути o. Пам'ятаєте, що ми збереглися -3в нижній частині стека безпосередньо перед тим, як натиснути перший l? Ми можемо використовувати це для розділення двох гілок.

        . . . .
        . . . .
        . . . .
        . . . .
. . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
6 t ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . . 
        . . . .
        . . . .

Стек починається як [..., -3 or 140, ...]

Explanation
6t?         
6t          Take the 6th item from the top and move
            it to the top (which is either -3 or 140)
  ?         If that's positive, turn right, otherwise,
            turn left

Спочатку 'l'

Якщо це було першим 'l', нам потрібно проштовхнути інше 'l'. Для збереження байтів ми використовуємо ті самі символи, що і для першого 'l'. Ми можемо спростити стек до [...]. Ось відповідна частина куба, яка не замінюється амперсандами.

        p > q '
        . . . .
        . . . .
        . . . .
' . q . . . . . . . . l . . . .
$ W W . . . . . . . . > & & & &
. . ? . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
        . . . .
        . . . .
        . . . .
        . . . .

Виконуються наступні інструкції:

$'pq'lq
$'          no-op
  pq        no-op
    'l      Push the character code of l
            Stack: [..., 108]
      q     Send it to the bottom
            Stack: [108, ...]

Ми збираємось увійти до циклу читання / запису, тому ми закінчили цю гілку.

Друге 'l'

Якщо вхід був другим 'l'в 'hello', IP повернув праворуч на знак питання. Ще раз ми можемо спростити стек до [...]і IP починається ?, вказуючи на південь.

        . . . .
        . . . .
        . . . .
        . . . .
. . . . . . . . . . . . . . . .
. . . u _ q < o ' \ . . . . . .
. . ? . . . . . . & . . . . . .
. . & . . . . . . & . . . . . .
        . . . .
        & & & &
        . . . .
        . . . .

Виконані інструкції:

'oq_
'o          Push the character code of 'o'
            Stack: [..., 111]
  q         Move the top item to the bottom
            Stack: [111, ...]
   _        No-op

І IP збирається знову ввести цикл читання / запису, тому ми також закінчили цю гілку.


Героїчні зусилля!

5

C ++, 142 141 байт

#import<iostream>
void f(std::istream&i){i>>std::noskipws;char c;for(std::string s="     ";s!="hello"&&i>>c;)s.erase(0,1),s+=c,std::cout<<c;}

Спробуйте в Інтернеті!


Чи можливо це зробити за допомогою GCC? Я не бачу #importв програмах GCC C ++ ...
ckjbgames

1
@ckjbgames #import- це застаріле розширення GCC.
Steadybox

1
@ckjbgames докладніше тут: stackoverflow.com/questions/172262 / ...
iFreilicht

@iFreilicht Це питання насправді змусило мене це задати.
ckjbgames

1
@ckjbgames Ви можете поглянути на другу відповідь: stackoverflow.com/a/172264/2533467 "Імпорт в gcc відрізняється від імпорту в VC ++. Це простий спосіб включити заголовок не більше одного разу. "
iFreilicht

3

Вузол, 124 байти

with(process)with(stdin)on('data',d=>[...d].map(c=>(s=(stdout.write(c),s+c).slice(-5))=='hello'&&exit()),setEncoding(),s='')

Не припускаючи, що потік вміститься у наявну пам'ять.


3

C #, 134 байти

using C=System.Console;class P{static void Main(){var s="";for(int c;(c=C.Read())>=0&!s.Contains("olleh");C.Write(s[0]))s=(char)c+s;}}

Спробуйте в Інтернеті

Читає персонаж, перевіряє, чи не -1 (EOS), і що ми ще не бачили "привіт", потім додає його до рядка і записує символ. Ми випереджати , тому що s[0]це набагато коротше (char)s. Це має квадратичну вартість у довжину рядка, оскільки вона повинна виділяти та сканувати весь вхід кожного разу, коли він читає символ (це вийде з ладу після 2 Гб вводу через обмеження в CLR, це дозволено?)

using C=System.Console;

class P
{
    static void Main()
    {
        var s="";
        for(int c;(c=C.Read())>=0&!s.Contains("olleh");C.Write(s[0]))
            s=(char)c+s;
    }
}

Версію (довше: 142 байти), у якої не вистачить пам’яті та яка має постійну вартість персонажу, див. Нижче:

using C=System.Console;class P{static void Main(){var s="     ";for(int c;(c=C.Read())>=0&s!="hello";C.Write(s[4]))s=s.Substring(1)+(char)c;}}

Цей зберігає останні 5 символів у 5-ти довжинній рядку, що означає короткі порівняння та дешевий пошук останнього чару, але оновити значно дорожче.

using C=System.Console;

class P
{
    static void Main()
    {
        var s="     ";
        for(int c;(c=C.Read())>=0&s!="hello";C.Write(s[4]))
            s=s.Substring(1)+(char)c;
    }
}

3

PHP, 57 55 53 байт

while(hello!=$s=substr($s.$c,-5))echo$c=fgetc(STDIN);

оскільки не існує нескінченних файлів, я беру вкладку від STDIN. Бігайте з -nr.

Проведіть цикл через введення, роздрукуйте поточний символ, додайте його $s, виріжте $sдо останніх 5 символів. Розрив петлі, коли $sє hello.


3

Vim, 39 байт

:im hello hello:se noma
:map : i

i

Спробуйте в Інтернеті!

:im hello                        "Remap 'hello' in insert mode to
          hello                "write hello, then hit escape
                 :se noma       "then set the buffer to not-modifiable
:map : i                        "THEN remap ':' to 'i' so that can't be changed

i                                "enter insert mode and await an infinite stream of input

Це прийнятий метод введення для Vim? Я думав, що програми Vim зазвичай очікують, що вхід вже буде в буфері до їх запуску.
Мартін Ендер

Якщо чесно, я не знаю? Це правда, але навряд чи дозволяє нескінченний потік, тому я просто зробив це таким чином, не думаючи, що так важко про це.
nmjcman101

Що станеться, якщо у вхідному потоці є символ втечі?
дим

@dim я запитав, і OP вказав лише друковані ASCII та нові рядки. ESC не включений до друку ASCII
afaik

3

PowerShell, 111 байт

Напевно, є кращий спосіб зробити це, але наразі я не бачу цього.

while(($x=($x+$host.UI.RawUI.ReadKey("IncludeKeyDown").character+"     ").substring(1,5)).CompareTo("hello")){}

Це читає ключові штрихи, не пригнічуючи відлуння. Символ додається до $ x, який обробляється останніми 5 символами та порівнюється з "привіт". Це триває, поки порівняння не буде правдивим.

Примітка: це не працює в PowerShell ISE. Програма ReadKey відключена в цьому середовищі.


3

Схема 115 байт

(do((c(read-char)(read-char))(i 0(if(eqv? c(string-ref"hello"i))(+ i 1)0)))((or(eof-object? c)(= i 5)))(display c))

Читаема версія:

(do ((c (read-char) (read-char))                            ; read stdin
     (i 0 (if (eqv? c (string-ref "hello" i)) (+ i 1) 0)))  ; check target
    ((or (eof-object? c) (= i 5))) ; finish if end of stdin, or word found
  (display c))                     ; display each character

Це знімає окремий знак від stdin кожного разу навколо циклу і відзначає його позицію на цільовому слові, коли він відповідає символам "привіт".

Зупиняється, коли вхід закінчується або бачиться "привіт". У нескінченному потоці не використовується пам'ять.


Класна відповідь, ласкаво просимо на сайт!
DJMcMayhem

3

AWK, 95 байт

BEGIN{RS="(.)"
split("hello",h,"")}{for(j=0;++j<6;){c=RT
printf c
if(c!=h[j])next
getline}exit}

Тут я навчився двом речам:
1) для розділення записів між символами використання, RS="(.)"а потім їх RTпотрібно використовувати замість $1
2) ORSвикористовується printі використовується за замовчуванням до "\n"
3) я не можу рахувати до 2 і використовуватиprintf "дешевше", ніж призначенняORS та використовуючиprint

Приклад використання: розмістіть код у FILE

awk -f FILE some_data_file

або

some process | awk -f FILE

Код був протестований за допомогою Денніса yes | ... пропозицією і я побачив багато і багато ys.

FYI, ви можете виконати завдання RS як варіант і витягнути його з BEGINблоку за допомогою:

awk -v RS='(.)'

Дійсно складне рішення! (Може бути , тому що в п'ятницю вдень, але я вважаю , це хороша запис заплутаним виклик теж.) Хоча я б спробувати більш awkish підхід: BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}.
манатура

Як не дивно, я майже точно відповідь готовий надіслати годину тому ... і забув її надіслати. : p
Роберт Бенсон

3

Python 3 (Linux), 73 72 байти

s=c='_';I=open(0)
while'olleh'!=s>''<c:c=I.read(1);s=c+s[print(end=c):4]

Дякуємо @MitchSchwartz за те, що гольф на 1 байт!

Спробуйте в Інтернеті!


Я не розумію. Як умова whileправильно оцінювати? Схоже, ви порівнюєте булеве значення з порожнім рядком.
iFreilicht

1
s[print(end=c):4]рятує байт
Мітч Шварц

1
@iFreilicht Python розбирає ланцюгові умови, як і в математиці (наприклад, a <b <c , наприклад). Умова є скороченою 'olleh'!=s and s>''and''<c). Середній тест не потрібен, але прив’язування їх коротше, ніж пряме 'olleh'!=s and''<c.
Денніс

@MitchSchwartz Це так. Дякую!
Денніс

3

8086 машинного коду, 22 байти

00000000  bf 11 01 b4 01 cd 21 ae  75 f6 81 ff 16 01 72 f3  |......!.u.....r.|
00000010  c3 68 65 6c 6c 6f                                 |.hello|
00000016

Еквівалентний код складання:

org 0x100
use16
a:  mov di, msg
b:  mov ah, 1       ; read one byte from stdin with echo
    int 0x21        ; dos syscall -> result in AL
    scasb           ; if (DI++ == AL)
    jne a
    cmp di, msg+5
    jb b
    ret
msg db "hello"

Як це працює?

1
Я додав еквівалентний код складання. В основному він покладається на один дуже корисний DOS-виклик DOS, який зчитує один байт зі stdin і одночасно повторює його назад до stdout. У 8086 також є однобайтова інструкція порівняння рядків, яка тут стане в нагоді.
користувач5434231

2

Pyth, 49 47 байт

Wn"hello"=>5+kp$__import__("sys").stdin.read(1)

Pyth не дуже добре сприймає один символ введення. Все в$__import__("sys").stdin.read(1) цьому просто робить. Також це означає, що це працює лише в режимі офлайн.

Все інше коротке ...

Програма - це тіло без циклу. Всередині умови програма зчитує символ, виводить його назад, додає цього символу k(що спочатку є порожнім рядком), обрізає всі, крім останніх 5 символів k, а потім перевіряє, що результат не є"hello" .

32 символи отримують один байт введення, 15 символів - решта.

Тестований на Linux, працює навіть без нового рядка, нескінченного введення тощо.


2

Луа, 68 64 байт

l=""while l~="hello"do c=io.read(1)io.write(c)l=l:sub(-4)..c end

1
Змініть нарізку на l:sub(-4), тоді ви можете зменшити ініціалізацію l="".
манарство

@manatwork Це акуратно. Дякую за пораду.
Blab


1

Рода , 49 47 байт

{a=[0]*5{|x|[x];a=a[1:]+x;z if[a&""="hello"]}_}

Спробуйте в Інтернеті!

Це анонімна функція, яка зчитує символи зі свого вхідного потоку та видає їх, поки не буде знайдено "привіт". Він використовує масивa для відстеження останніх символів.

Він виводить трохи сміття на STDERR, але я зрозумів, що це дозволено .

Пояснення:

{
    a=[0]*5                /* Initialize the array with 5 zeroes. */
    {|x|                   /* For each x in the input stream: */
        [x];               /* Print x */
        a=a[1:]+x;         /* Add x and remove the sixth last character. */
        z if[a&""="hello"] /* If "hello" is found, crash the program */
                           /* with an undefined variable. */
    }_                     /* End for loop. */
}

Де знаходиться документація Roda?
ckjbgames

@ckjbgames Тут. Я використовую останню версію 0,12, яка є у власній філії в Github.
fergusq

1

Ява 7, 122 118 124 123 150 141 байт

void c()throws Exception{String a="aaaaa";for(int b;!a.equals("hello")&(b=System.in.read())>=0;a=a.substring(1)+(char)b)System.out.write(b);}

Тепер зупиняється, коли буде досягнутий кінець потоку. Тепер обробляє нескінченний вхід, не втрачаючи пам'яті.


Б'юсь об заклад, що це не вдається виправити нескінченний внесок.
Тит

@Titus fix ...
Poke

Я поклонився, не бачачи, щоб writeйого використовували замість print. Я не можу скасувати свій голос, вибачте за це :(
Олів'є Грегоар

1

Рубі, 51 байт

x="";$><<x[-1]while/hello./!~x=x[/.{0,5}$/]+$<.getc
  • Не очікує нових рядків
  • Працює з нескінченним вкладом

1

AHK , 116 байт

Loop,Read,%1%
{a=%A_LoopReadLine%`n
Loop,Parse,a
{Send % c:=A_LoopField
If((f:=c SubStr(f,1,4))=="olleh")
ExitApp
}}

Насправді немає нічого розумного чи магічного. Змінна %1%є першим переданим аргументом і має бути шлях до файлу з потоком. Файл повинен бути збережений у міру оновлення, але код буде прочитаний до кінця, навіть якщо він розшириться після початку читання.


1

Математика, 107 байт

i="";EventHandler[Dynamic@i,"KeyDown":>(i=i<>CurrentValue@"EventKey";If[StringTake[i,-5]=="hello",Exit[]])]

Вихід стає полем, де користувач може нескінченно вводити текст (включаючи нові рядки), поки останні 5 символів не дорівнюють "hello"; в цей момент він виходить.


1

мозковий ебать , 281 байт

>++++++++[<+++++++++++++>-]>++++++++++[<++++++++++>-]<+>>+++++++++[<++++++++++++>-]>++++++++++[<+++++++++++>-]<+>+[[[[[,.<<<<[->>>>->+<<<<<]>>>>>[-<<<<<+>>>>>]<],.<<<[->>>->+<<<<]>>>>[-<<<<+>>>>]<],.<<[->>->+<<<]>>>[-<<<+>>>]<],.<<[->>->+<<<]>>>[-<<<+>>>]<],.<[->->+<<]>>[-<<+>>]<]

Я не впевнений, чому, але я просто відчував, що мозковий ебать це правильна річ. Не вимагає нескінченної пам’яті і може виводити назавжди.

Пояснив

Set up the buffers with helo
This is done Naively; sue me
>++++++++[<+++++++++++++>-]     h
>++++++++++[<++++++++++>-]<+>   e
>+++++++++[<++++++++++++>-]     l
>++++++++++[<+++++++++++>-]<+>  o

THE MAIN LOOP
+
[ matches o
    [ matches l
        [ matches l
            [ matches e
                [ matches h
                    ,. Read a character and immediently write it
                    <<<<[->>>>->+<<<<<] Subtract it from h
                    >>>>>[-<<<<<+>>>>>] Correct the h
                    < Terminate this part of the loop if it matches h
                ]
                ,. Same as above
                <<<[->>>->+<<<<] Subtract it from e
                >>>>[-<<<<+>>>>] Correct the e
                < Terminate this part of the loop if it matches e
            ]
            ,. Same as above
            <<[->>->+<<<] Subtract it from l
            >>>[-<<<+>>>] Correct the l
            < Terminate this part of the loop if it matches l
        ]
        ,. Same as above
        <<[->>->+<<<] Subtract it from l
        >>>[-<<<+>>>] Correct the l
        < Terminate this part of the loop if it matches l
    ]
    ,. Same as above
    <[->->+<<] Subtract it from o
    >>[-<<+>>] Correct the o
    < Terminate this part of the loop if it matches o
]

Спробуйте в Інтернеті!


Я збирався зробити це так, але потім зрозумів, що це виводить нульовий байт нескінченно для вводу, який не містить "привіт": tio.run/nexus/…
KarlKastor

Це також не вдається ahehellob.
Мітч Шварц
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.