Miałeś mnie na cześć


30

Zadanie

Wczytaj prawdopodobnie nieskończony strumień tekstowy lub plik, wyświetlając jego zawartość, aż słowo hellozostanie wypisane, zgodnie z następującymi zasadami.

  • Po hellowygenerowaniu kod powinien zostać natychmiast zamknięty. Nie powinien na przykład czekać na nową linię.

  • Twój kod powinien wypisywać na bieżąco. Oznacza to, że nie powinien czytać dużej ilości danych wejściowych, a następnie zacząć generować.

  • Jeśli strumień / plik nie zawiera hello, Twój kod powinien po prostu wyprowadzać dane wejściowe na zawsze lub do końca strumienia / pliku.

  • Jest to wyzwanie uwzględniające wielkość liter, więc hellonie jest równe Hello.

  • Możesz założyć, że dane wejściowe składają się wyłącznie z drukowalnych znaków ASCII i znaków nowej linii.

  • Twój kod nie może oczekiwać, że tekst zostanie zakończony znakiem nowej linii lub że na wejściu będą w ogóle jakieś nowe linie. Ponadto kod nie może zakładać, że będzie działał na komputerze z nieskończoną ilością pamięci.

  • Możesz założyć, że twój kod zostanie wywołany z pustego katalogu.

Przykładowy strumień wejściowy

I once had a horse called hellopina.

Wydajność

I once had a horse called hello

Wskazówka

Uruchom, yes | tr -d \\n | <your program>aby sprawdzić, czy działa z nieskończonymi strumieniami. Jeśli nic nie drukuje i / lub wycieka pamięć, program nie jest zgodny ze specyfikacją. Powinien drukować yyyyyyyyyyyyyyyyyyyyyy...wiecznie, bez nowych linii.


1
Czy wolno nam coś przeczytać po „cześć”? Pytanie wydaje się zabraniać jakiegokolwiek dodatkowego odczytu, co może być problematyczne w językach takich jak (Standard) C, które zapewniają buforowane dane wejściowe z automatycznym wyprzedzeniem odczytu.
Toby Speight

Prawdopodobnie powinieneś zmienić zaakceptowaną odpowiedź na asembler, ponieważ jest ona o 2 bajty krótsza.
Rɪᴋᴇʀ

@Riker Byłoby wspaniale, gdyby ktoś mógł to przetestować lub przynajmniej powiedzieć, że wierzy, że najpierw działa.

Odpowiedzi:


2

Galaretka , 24 bajty

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

Wypróbuj online!

Wyjaśnienie:

ṫ-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 bajtów

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

Wypróbuj online!

Jak to działa

To jest pełny program. Definiujemy funkcję f dla naszych celów. Aby zapisać bajty, zadeklarowany jest dwoma argumentami domyślnie int . Jest to zachowanie nieokreślone, ale w praktyce n zostanie zainicjowane jako 1 podczas uruchamiania programu bez dodatkowych argumentów, c zachowa 32 dolne bity wskaźnika do wektora argumentu

Podczas gdy warunek

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

posiada będziemy wykonać podczas gdy ciało pętli za:

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

Aby w pełni zrozumieć ten warunek, musimy najpierw zbadać ciało. Na razie obserwujemy tylko, że c=getchar()czyta pojedynczy bajt ze STDIN (jeśli to możliwe) i przechowuje go w zmiennej c .

Cześć sekwencji bajtów wygląda następująco w różnych reprezentacjach.

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

Wszystkie z nich mieszczą się w przedziale [96, 192) , więc c/96zostaną ocenione na 1 dla każdego z tych bajtów i na 0 dla wszystkich pozostałych znaków ASCII. W ten sposób putchar(c)/96*c( putchar wypisuje i zwraca argument) oceni na c, jeśli c jest `, małą literą, jednym z {|}~lub znakiem DEL; dla wszystkich innych znaków ASCII będzie miało wartość 0 .

n jest aktualizowany poprzez przesunięcie go o pięć bitów w lewo, a następnie XOR wyniku z wynikiem z poprzedniego akapitu. Ponieważ int ma szerokość 32 bitów (a przynajmniej tak zakładamy w tej odpowiedzi), niektóre z przesuniętych bitów mogą „spaść z lewej strony” (przepełnienie liczby całkowitej ze znakiem jest zachowaniem niezdefiniowanym, ale gcc zachowuje się jak generowana tutaj instrukcja x64). Zaczynając od nieznanej wartości n , po zaktualizowaniu jej dla wszystkich znaków hello , otrzymujemy następujący wynik.

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

Zauważ, że dolne 25 bitów tworzy liczbę całkowitą 0xb33def , która jest magiczną stałą w tym stanie. Podczas gdy bitów dwóch sąsiednich bajtów zachodzi pewne nakładanie się, bajty odwzorowania poniżej 96 na 0 zapewniają, że nie ma żadnych fałszywych alarmów.

Warunek składa się z dwóch części:

  • ~(getchar()) pobiera bitową NIE wyniku odczytu (lub próby odczytu) bajtu ze STDIN.

    Jeśli getchar powiedzie, to zwróci wartość odczytu bajtu jako int . Ponieważ dane wejściowe składają się wyłącznie ze znaków ASCII, odczytany bajt może mieć ustawione tylko 7 niższych bitów, więc bitowe NIE będzie miało w tym przypadku swoich najwyższych 25 bitów.

    Jeśli getchar nie powiedzie się (nie ma więcej danych wejściowych), zwróci -1, a bitowe NIE będzie wynosić 0 .

  • n-0xb33def<<7odejmuje stałą magiczną od poprzedniej od n , a następnie przesuwa wynik o 7 jednostek w lewo.

    Jeśli ostatnie 5 odczytanych bajtów było hello , najniższe 25 bitów n będzie równe 0xb33def i odjęcie ich wyzeruje . Przesunięcie różnicy da 0, ponieważ 7 najwyższych bitów „spadnie z lewej”.

    Z drugiej strony, jeśli ostatnie 5 odczytanych bajtów nie było przywitanych , ustawiony zostanie jeden z 25 najniższych bitów różnicy; po zmianie jeden z najwyższych 25 bitów będzie.

Na koniec, jeśli getchar się powiódł i jeszcze nie wypisaliśmy cześć , bitowe ORAZ, wszystkie najwyższe 25 bitów lewego operandu i co najmniej jeden z najwyższych 25 bitów prawego operandu zostaną ustawione. W ten sposób &da niezerową liczbę całkowitą i pętla będzie kontynuowana.

Z drugiej strony, jeśli dane wejściowe są wyczerpane lub już wydrukowaliśmy hello , jeden z bitowych argumentów AND będzie równy zero, a więc i wynik. W takim przypadku przerywamy pętlę i program się kończy.


Prawdopodobnie powinieneś wspomnieć, że zależy to od wejścia zakodowanego w ASCII, zanim zagłębisz się w wyjaśnienie.
Toby Speight

2
@TobySpeight Nie wydaje mi się, że jest to typowe. Jakiego rodzaju niekompatybilnego kodowania ASCII spodziewałbyś się użyć odpowiedzi w języku C?
Dennis,

EBCDIC to oczywiste kodowanie, które nie jest ASCII. C nie określa żadnego konkretnego kodowania znaków (tylko, że cyfry dziesiętne muszą być reprezentowane kolejnymi wartościami, w kolejności).
Toby Speight

powyższy program zatrzymuje się, jeśli strumień zawiera ciąg nie ascii "« úá ÷ o "1: o 111 6f 2: ÷ 246 f6 3: á 160 a0 4: ú 163 5:« 174
RosLuP 10.04.17

@RosLuP Specyfikacja wyzwania gwarantuje, że dane wejściowe będą się składały z drukowalnych znaków ASCII i znaków nowej linii.
Dennis

19

Bash, 74 75 103 99 88 82 76 bajtów

-10 bajtów dzięki @DigitalTrauma!
-11 bajtów dzięki @manatwork!
-6 bajtów dzięki @Dennis!

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

Wyjaśnienie:

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

Wypróbuj online!


2
To jest świetne! Miałem nadzieję, że odpowiedź będzie szybka.

13

Labirynt , 43 41 bajtów

Dzięki Sp3000 za oszczędność 2 bajtów.

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

Wypróbuj online!

Wyjaśnienie

Podstawową ideą jest zakodowanie pięciu ostatnich znaków w bazie 256 w jednej liczbie całkowitej. Kiedy pojawia się nowy znak, możemy go „dodać”, mnożąc liczbę całkowitą przez 256 i dodając nowy punkt kodowy. Jeśli chcemy spojrzeć tylko na 5 ostatnich znaków, bierzemy wartość modulo 256 5 = 2 40 = 1099511627776. Następnie możemy po prostu sprawdzić, czy wartość ta jest równa 448378203247, co otrzymujemy, gdy traktujemy punkty kodu hellojako podstawowe 256 cyfr.

Co do kodu ... <...>to trochę idiom Labiryntu. Pozwala napisać nieskończoną pętlę bez żadnego warunkowego przepływu sterowania w pojedynczej linii, oszczędzając wiele bajtów na spacjach i liniach. Głównym warunkiem tego działania jest to, że po osiągnięciu stosu znajdują się dwie wartości jednorazowe <(zwykle używamy 0do tego celu s, ale rzeczywista wartość jest dowolna).

Oczywiście program potrzebuje pewnej logiki warunkowej, aby dowiedzieć się, kiedy zakończyć. Ale warunkowo zakończenie programu jest możliwe poprzez podzielenie przez wartość równą zero, gdy chcemy, aby program się zakończył. Te <...>prace konstrukt przez przeniesienie całego wiersza w lewo (cyklicznie), gdy IP jest na lewym końcu, a następnie przeniesienie go natychmiast z powrotem na miejsce. Oznacza to, że kod jest faktycznie wykonywany od prawej do lewej. Odwróćmy to:

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

Jest to jedna iteracja pętli, która odczytuje znak, kończy się, jeśli osiągnęliśmy EOF, drukuje znak, dodaje go do naszego kodowania, obcina to do 5 znaków, sprawdza równość helloi powtarza. Oto jak to działa szczegółowo (pamiętaj, że Labirynt jest oparty na stosie):

_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 bajtów

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

Ponad 500 bajtów to stałe, które muszę trochę zagrać w golfa.

Zasadniczo jest to maszyna stanu, więc nieskończone wprowadzanie danych nie stanowi problemu.

To jest lekko skomentowana wersja

+
[
  >,.
  >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]
            <->>
          ]
        ]
      ]
    ]
  ]
  <<
]

To wygląda zabawnie :)

Witamy w Programowaniu zagadek i Code Golf StackExchange!
betseg

1
Ten kod ma wiele problemów, ale największym problemem jest to, że nie zawiera logiki do obsługi spraw, jak ahehellobpoprawnie; w środku potencjalnego dopasowania sprawdza tylko kolejną literę helloi nie szuka hpoczątku.
Mitch Schwartz,

8

Bash , 73 68 66 bajtów

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

Zakłada katalog, w którym nie ma lub ma tylko ukryte pliki. Musi być uruchomiony jako <path/to/script>.

Wypróbuj online!

Jak to działa (nieaktualne)

Na początku while pętli, to pierwszy test, jeśli ciąg w zmiennej s (początkowo pustego) równa olleh ( cześć tyłu, Ole) i powrócić 0 (mecz) lub 1 (nie mecz) odpowiednio. Chociaż formalnie jest częścią warunku pętli, wynik nie wpłynie na nią samodzielnie, ponieważ tylko ostatnie polecenie dookreśla, czy warunek się utrzymuje.

Następnie ustawiamy wewnętrzny separator pól na pusty ciąg (aby readnie dusił się na białych znakach), odczytuje surowe bajty ( -r) ze STDIN i przechowujemy je c. $?jest kodem wyjścia poprzedniego polecenia, więc odczytuje dokładnie jeden -N1bajt ( ) dla niepasującego i zero bajtów ( -N0). Odczyt zerowych bajtów, czy to z powodu trafienia w EOF, czy dlatego, że -N0został określony, powoduje readzakończenie z kodem stanu 1 , więc pętla while zakończy się; w przeciwnym razie ciało zostanie wykonane i zaczniemy od nowa.

W organizmie, najpierw wydrukować bajt czytamy, potem zmiana s z s=$c${s::4}. To dodaje bajt odczytu do (do) pierwszych czterech bajtów s , więc s będzie równe olleh po wydrukowaniu hello .


Naprawdę bardzo ładnie!

8

pieprzenie mózgu, 117 bajtów

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

Sformatowany:

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

Wypróbuj online .

Inicjuje taśmę z helloprzesuniętymi znakami 107, rozmieszczonymi z jedną wartością co trzy komórki, a następnie śledzi ostatnie pięć znaków i sprawdza dopasowanie każdego nowego przetworzonego znaku, używając flagi po prawej stronie ciągu, aby śledź, czy doszło do dopasowania.


7

Rubinowy , 46 60 bajtów

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

Wypróbuj online!

Odczytuje znaki od standardowego wejścia do ostatnich 5 hello, a następnie wyświetla ciąg znaków (lub dopóki w standardowym standardzie nie pozostaną żadne znaki). Kończy się z błędem.

Równoważny:

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

Lub bardziej nie golfisty:

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

1
arośnie za każdym razem, gdy czytany jest znak. Czy to ulega awarii, jeśli dane wejściowe są nieskończone?
betseg

@betseg hm, może. Zobaczę, czy mogę to naprawić
Conor O'Brien,

7

Python 3, 120 116 104 bajtów

Działa z nieskończonymi strumieniami, po raz pierwszy w golfa, wszelkie wskazówki są mile widziane.

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

Dzięki @DJMcMayhem za zapisanie niektórych bajtów :)


Witamy na stronie! c=[0,c+1]['hello'[c]==a]powinien zaoszczędzić trochę bajtów. Również a=1jest krótszy.
DJMcMayhem

2
W whilePythonie nie potrzebujesz nawiasu .
PurkkaKoodari

6

Haskell, 41 47 43 bajtów

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

Leniwość Haskella dobrze sobie radzi z nieskończonym wyjściem / wyjściem.

Wypróbuj online!

Edycja: nie obsługuje wejścia skończonego - naprawiono. Dzięki @Leo za wskazanie.

Edycja II: @ Ørjan Johansen zapisał 4 bajty. Dzięki!


2
Dane wejściowe mogą być również skończone, więc myślę, że musisz zająć się sprawą, gdy dotrzesz do końca łańcucha
Leo

@Leo: Ups, całkowicie tego przegapiłem. Naprawiony.
nimi

2
Pierwszy strażnik można skrócić |w@"hello"<-take 5l=w.
Ørjan Johansen

@ ØrjanJohansen: och, to miłe. Dzięki!
nimi

6

Cubix, 94 83 82 79 63 56 bajtów

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

Rozszerzony:

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

Notatki

  • Interpretator wyłącza pole wprowadzania podczas uruchamiania programu. W związku z tym nieskończony strumień danych wejściowych jest niemożliwy. Ten program pobiera dane wejściowe znak po znaku, więc gdyby nie to ograniczenie, działałoby poprawnie.
  • Ten program nie usuwa stosu i bardzo szybko się psuje. Ponieważ maszyna, która zostanie użyta, najwyraźniej może dawać nieskończone strumienie wejściowe, rozsądne wydaje się założenie, że ma ona również nieskończoną pamięć.
  • Każda pomoc golfa jest bardzo ceniona.

Wypróbuj online

Możesz wypróbować program tutaj .

Wyjaśnienie

Główny pomysł

Ogólna idea polega na tym, że chcemy odczytać znak, a następnie porównać go z różnymi znakami (najpierw h, potem epoteml itd.). Aby śledzić postać, którą przegapiliśmy, trzymamy ją na samym dole stosu. Kiedy go potrzebujemy, możemy z łatwością przenieść go na szczyt.

Pętla odczytu / zapisu

Pętla do odczytu i zapisu jest po prostu piątą linią. Wszystkie nieużywane znaki są zastępowane przez no-ops ( .):

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

Można to podzielić na dwie części: czytanie i (pisanie i sprawdzanie). Pierwsza część zawiera instrukcje do znaku zapytania włącznie. Druga część w górę to reszta linii. Ponieważ to się zapętla, zakładamy, że zaczynamy od stosu[...]

    @
'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

Druga część (pisanie i sprawdzanie) jest znowu liniowa. Stos zaczyna się jako [next-char, ..., input]. Wyodrębniliśmy kolejny znak, ponieważ zmienia się on później w programie.

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.

Teraz IP zacznie się ponownie na początku tej pętli, resetując następny znak do sprawdzenia h.

Dopasowywanie następnego znaku

Jeśli adres IP wykonał zwrot (tj. Znak, który przeczytaliśmy i wydrukowaliśmy, pasował do następnego znaku 'hello'), musimy sprawdzić, jaki znak był wejściem i, zależnie od tego, przesunąć następny znak na dół stosu. Następnie musimy powrócić do pętli odczytu / zapisu bez pchania hdo stosu, więc potrzebujemy innego sposobu, aby się tam dostać.

Po pierwsze: określ, jaki znak był wprowadzony. Stos wygląda tak: [..., prev-char, input, 0].

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

Aby porównać dane wejściowe, ponownie użyjemy kodu znakowego h. Początkowo było tak, ponieważ tak naprawdę nie wiedziałem, jak sobie z tym poradzić i hjest to pierwszy znak w ciągu, który można sprawdzić, ale okazało się to dość wygodne. Jeśli odejmiemy kod znakowy h od danych wejściowych, otrzymamy, -3jeśli dane wejściowe są e, 0jeśli dane wejściowe są h, 4jeśli dane wejściowe są li 7jeśli dane wejściowe są o.

Jest to przydatne, ponieważ ?polecenie pozwala nam łatwo oddzielić wartości ujemne od wartości dodatnich od zera. Jako taki, jeśli IP skręca w lewo, różnica była ujemna, więc wejście było e, więc następny znak powinien być l. Jeśli adres IP kontynuuje prostą różnicę, różnica była 0, więc wejście było h, więc następnym znakiem powinien być znak e. Jeśli dane wejściowe to an llub ano , adres IP skręca w prawo.

Wszystkie instrukcje wykonane przed wspomnianym znakiem zapytania to:

;!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]

Teraz adres IP zmienia swój kierunek, jak opisano powyżej. Omówmy różne możliwości.

Wkład 'e'

Najpierw rozważymy dane wejściowe e, które powodują przesunięcie adresu IP w górę od ?, ponieważ różnica wynosi 3. Wszystkie nieistotne znaki zostały usunięte z kostki.

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

Znaki są wykonywane w tej kolejności (z wyłączeniem niektórych znaków przepływu kontrolnego):

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, ...]

Teraz adres IP ponownie osiągnął pętlę odczytu / zapisu.

Wkład 'h'

Jeśli wejście było 'h', różnica wynosi 0, więc adres IP nie zmienia swojego kierunku. Oto znowu kostka, z usuniętymi wszystkimi nieistotnymi postaciami. Ponieważ ta ścieżka zawiera sporo no-opów, wszystkie przejrzane przez nią no-ops zostały zastąpione &. Adres IP zaczyna się od znaku zapytania.

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

Wykonywane instrukcje to:

'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

A teraz znów wchodzimy w pętlę odczytu / zapisu, więc gotowe.

Inne dane wejściowe

Wszystkie pozostałe dane wejściowe powodują różnicę dodatnią, więc adres IP skręca w prawo przy znaku zapytania. Nadal musimy oddzielić li o, więc to zrobimy dalej.

Oddzielając 'l'i'o'

Należy pamiętać, że różnica wynosi 7 dla oi 4 dla li że musimy zakończyć program, jeśli dane wejściowe to o. Oto znowu sześcian z nieistotnymi częściami zastąpionymi przez a, .a no-ops krzyże IP zostały zastąpione znakami ampersands.

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

Rozróżnianie między nimi 'l' s

Teraz wiemy, że dane wejściowe były l, ale nie wiemy, który l. Jeśli jest to pierwszy, musimy przesunąć kolejny lna spód stosu, ale jeśli jest to drugi, musimy przesunąć o. Pamiętasz, jak zapisaliśmy -3się na dole stosu tuż przed wypchnięciem pierwszego l? Możemy to wykorzystać do rozdzielenia dwóch gałęzi.

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

Stos zaczyna się jako [..., -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

Pierwszy 'l'

Jeśli to był pierwszy 'l', musimy wcisnąć kolejny 'l'. Aby zapisać bajty, używamy tych samych znaków, co dla pierwszego 'l'. Możemy uprościć stos do[...] . Oto odpowiednia część kostki, bez przestojów zastąpionych znakami ampersands.

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

Wykonywane są następujące instrukcje:

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

Wkrótce przejdziemy do pętli odczytu / zapisu, więc skończyliśmy z tą gałęzią.

druga 'l'

Jeśli wejście był drugim 'l'w 'hello', IP skręcił w prawo na znak zapytania. Po raz kolejny możemy uprościć stos, [...]a adres IP zaczyna się od ?, wskazując tym razem na południe.

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

Wykonywane instrukcje to:

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

I adres IP niedługo wejdzie w pętlę odczytu / zapisu, więc skończyliśmy również z tą gałęzią.


Heroiczny wysiłek!

5

C ++, 142 141 bajtów

#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;}

Wypróbuj online!


Czy byłoby to możliwe dzięki GCC? Nie widzę #importw programach GCC C ++ ...
ckjbgames

1
@ckjbgames #importto przestarzałe rozszerzenie GCC.
Steadybox

1
@ckjbgames więcej informacji tutaj: stackoverflow.com/questions/172262/…
iFreilicht,

@ iFreilicht To pytanie sprawiło, że zadałem to pytanie.
ckjbgames

1
@ckjbgames możesz rzucić okiem na drugą odpowiedź: stackoverflow.com/a/172264/2533467 „Import w gcc różni się od importu w VC ++. Jest to prosty sposób na dołączenie nagłówka co najwyżej raz. „
iFreilicht,

3

Węzeł, 124 bajty

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

Nie zakładając, że strumień zmieści się w dostępnej pamięci.


3

C #, 134 bajty

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;}}

Wypróbuj online

Odczytuje znak, sprawdza, czy nie jest to -1 (EOS) i czy jeszcze nie widzieliśmy „cześć”, a następnie przygotowuje go do łańcucha i wypisuje znak. Przygotowujemy się, ponieważ s[0]jest znacznie krótszy niż (char)s. Ma to kwadratowy koszt w długości ciągu, ponieważ musi on przydzielić i przeskanować całe dane wejściowe za każdym razem, gdy czyta znak (spowoduje to awarię po 2 GB danych wejściowych z powodu ograniczeń w CLR, czy to jest dozwolone?)

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;
    }
}

W przypadku wersji (dłuższej: 142 bajty), której nie zabraknie pamięci i która ma stały koszt na znak, patrz poniżej:

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;}}

Ten utrzymuje 5 ostatnich znaków w ciągu 5-długości, co oznacza krótkie porównania i tanie wyszukiwanie ostatniego znaku, ale jego aktualizacja jest znacznie droższa.

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 bajtów

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

ponieważ nie ma nieskończonych plików, pobieram dane wejściowe ze STDIN. Uruchom z -nr.

Zapętlaj dane wejściowe, drukuj bieżący znak, dołącz go $s, przycinaj $sdo ostatnich 5 znaków. Przerwij pętlę, gdy $sjest hello.


3

Vim, 39 bajtów

:im hello hello:se noma
:map : i

i

Wypróbuj online!

: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

Czy to akceptowana metoda wprowadzania dla Vima? Myślałem, że programy Vima zwykle oczekują, że dane wejściowe będą już w buforze przed ich uruchomieniem.
Martin Ender

Szczerze mówiąc nie wiem? To prawda, ale prawie nie pozwala na nieskończony strumień, więc zrobiłem to w ten sposób, nie zastanawiając się nad tym tak ciężko.
nmjcman101

Co się stanie, jeśli w strumieniu wejściowym znajduje się znak zmiany znaczenia?
dim

@dim zapytałem, a OP określił tylko ASCII do druku i znaki nowej linii. ESC nie jest uwzględniony w drukowanym ASCII
afaik

3

PowerShell, 111 bajtów

Prawdopodobnie jest na to lepszy sposób, ale w tej chwili tego nie widzę.

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

Odczytuje naciśnięcia klawiszy bez tłumienia echa. Znak jest dodawany do $ x, który jest przycinany do ostatnich 5 znaków i porównywany z „hello”. Trwa to do momentu, aż porównanie będzie prawdziwe.

Uwaga: to nie działa w programie PowerShell ISE. ReadKey jest wyłączony w tym środowisku.


3

Schemat 115 bajtów

(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))

Wersja do odczytu:

(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

To pobiera indywidualny znak ze standardowego wejścia za każdym razem w pętli i zaznacza jego pozycję na słowie docelowym, gdy spotyka znaki „cześć”.

Zatrzymuje się, gdy skończy się wejście lub pojawiło się „cześć”. Brak pamięci w strumieniu nieskończonym.


Fajna odpowiedź, witamy na stronie!
DJMcMayhem

3

AWK, 95 bajtów

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

Nauczyłem się tutaj 2 rzeczy:
1) Aby podzielić rekordy między postaciami, RS="(.)"a następnie RTmuszą być użyte zamiast $1
2) ORSjest używany przez printi ma domyślną wartość "\n"
3) Nie mogę liczyć na 2, a używanie printfjest „tańsze” niż przypisywanieORS i za pomocąprint

Przykładowe użycie: Umieść kod w PLIKU

awk -f FILE some_data_file

lub

some process | awk -f FILE

Kod został przetestowany przy użyciu yes | ...sugestii Dennisa i widziałem wieley s.

Do twojej wiadomości, możesz wykonać przypisanie RS jako opcję i wyciągnąć go z BEGINbloku poprzez:

awk -v RS='(.)'

Naprawdę trudne rozwiązanie! (Może dlatego, że to piątek po południu, ale uważam, że dobrą pozycję dla zaszyfrowanej wyzwanie zbyt). Choć chciałbym spróbować bardziej awkish podejście: BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}.
manatwork

Co dziwne, prawie dokładnie mam odpowiedź gotową do przesłania godzinę temu ... i zapomniałem ją przesłać. : p
Robert Benson,

3

Python 3 (Linux), 73 72 bajty

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

Dzięki @MitchSchwartz za grę w golfa na 1 bajcie!

Wypróbuj online!


Nie rozumiem. Jak whileprawidłowo ocenia się warunek ? Wygląda na to, że porównujesz wartość logiczną z pustym ciągiem.
iFreilicht 06.04.17

1
s[print(end=c):4]zapisuje bajt
Mitch Schwartz

1
@iFreilicht Python analizuje powiązane łańcuchy warunkowe tak, jak w matematyce ( na przykład a <b <c ). Warunek jest skrótem od 'olleh'!=s and s>''and''<c). Środkowy test nie jest potrzebny, ale łączenie ich w łańcuch jest krótsze niż proste 'olleh'!=s and''<c.
Dennis,

@MitchSchwartz That it does. Dziękuję Ci!
Dennis

3

Kod maszynowy 8086, 22 bajty

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

Równoważny kod zespołu:

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"

Jak to działa?

1
Dodałem równoważny kod zestawu. Zasadniczo polega na jednym bardzo przydatnym syscall DOS, który odczytuje jeden bajt ze standardowego wejścia i wysyła go z powrotem na standardowe wyjście. 8086 ma również instrukcję porównywania ciągów jednobajtowych, która jest tu przydatna.
user5434231 17.04.17

2

Pyth, 49 47 bajtów

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

Pyth nie jest zbyt dobry w przyjmowaniu jednego znaku wejściowego. Wszystko w$__import__("sys").stdin.read(1) po prostu to robi. Oznacza to również, że działa to tylko w trybie offline.

Wszystko inne jest krótkie ...

Program jest bezcielesny podczas pętli. Wewnątrz warunku program odczytuje znak, drukuje go z powrotem, dołącza ten znak do k(który początkowo jest pustym ciągiem), przycina wszystkie oprócz ostatnich 5 znaków k, a następnie sprawdza, czy wynik nie jest "hello".

32 znaki otrzymują jeden bajt danych wejściowych, 15 znaków zajmuje resztę.

Testowany na Linuksie, działa nawet bez znaku nowej linii, nieskończonego wejścia itp.


2

Lua, 68 64 bajtów

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

1
Zmień krojenie na l:sub(-4), a następnie możesz zmniejszyć inicjalizację l="".
manatwork

@manatwork To miłe. Dzięki za wskazówkę.
Blab


1

Röda , 49 47 bajtów

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

Wypróbuj online!

Jest to anonimowa funkcja, która odczytuje znaki ze strumienia wejściowego i wysyła je do momentu znalezienia „cześć”. Używa tablicya do śledzenia ostatnich znaków.

Wysyła jakieś śmieci do STDERR, ale zrozumiałem, że tak dozwolone .

Wyjaśnienie:

{
    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. */
}

Gdzie jest dokumentacja Roda?
ckjbgames

@ckjbgames tutaj. Korzystam z najnowszej wersji 0.12, która znajduje się we własnym oddziale w Github.
fergusq

1

Java 7, 122 118 124 123 150 141 bajtów

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);}

Teraz zatrzymuje się po osiągnięciu końca strumienia. Teraz obsługuje nieskończone wprowadzanie danych bez wyczerpywania się pamięci.


Założę się, że nie jest w stanie obsłużyć nieskończonych danych wejściowych.
Tytus

@Titus naprawiono ...
Poke

Przegłosowałem, nie widząc, writeże ktoś mnie używa print. Nie mogę cofnąć mojej opinii, przepraszam za to :(
Olivier Grégoire,

1

Rubinowy, 51 bajtów

x="";$><<x[-1]while/hello./!~x=x[/.{0,5}$/]+$<.getc
  • Nie oczekuje nowych linii
  • Działa z nieskończonym wejściem

1

AHK , 116 bajtów

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

Naprawdę nie ma w tym nic mądrego lub magicznego. Zmienna %1%jest pierwszym przekazywanym argumentem i powinna być ścieżką do pliku ze strumieniem. Plik musi zostać zapisany podczas aktualizacji, ale kod zostanie odczytany do końca, nawet jeśli rozszerzy się po rozpoczęciu odczytu.


1

Mathematica, 107 bajtów

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

Dane wyjściowe stają się polem, w którym użytkownik może bez końca pisać tekst (w tym znaki nowej linii), aż 5 ostatnich znaków będzie równych "hello"; w tym momencie wychodzi.


1

pieprzenie mózgu , 281 bajtów

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

Nie jestem pewien, dlaczego, ale po prostu czułem, że pieprzenie mózgu jest właściwe. Nie wymaga nieskończonej pamięci i może generować na zawsze.

Wyjaśnił

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
]

Wypróbuj online!


Zrobiłem to w ten sposób, ale potem zdałem sobie sprawę, że to nieskończenie wyświetla bajt zerowy dla danych wejściowych, które nie zawierają „hello”: tio.run/nexus/…
KarlKastor

To również zawiedzie ahehellob.
Mitch Schwartz,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.