Você me teve no olá

30

Tarefa

Leia um arquivo ou fluxo de texto possivelmente infinito, produzindo seu conteúdo até que a palavra helloseja impressa, respeitando as seguintes regras.

  • Após a hellosaída, seu código deve sair imediatamente. Não deve esperar por uma nova linha, por exemplo.

  • Seu código deve sair como segue. Ou seja, não deve ler uma quantidade enorme de entrada e começar a produzir.

  • Se o fluxo / arquivo não contiver hello, seu código deve continuar produzindo a entrada para sempre ou até o final do fluxo / arquivo.

  • Este é um desafio que diferencia maiúsculas de minúsculas, portanto hellonão é igual a Hello.

  • Você pode assumir que a entrada consiste apenas em caracteres ASCII imprimíveis e novas linhas.

  • Seu código não pode esperar que o texto seja finalizado por uma nova linha ou que haja novas linhas na entrada. Além disso, o código não pode assumir que ele será executado em uma máquina com uma quantidade infinita de memória.

  • Você pode assumir que seu código será chamado de um diretório vazio.

Exemplo de fluxo de entrada

I once had a horse called hellopina.

Saída

I once had a horse called hello

Gorjeta

Execute yes | tr -d \\n | <your program>para verificar se ele funciona com fluxos infinitos. Se não imprimir nada e / ou vazar memória, o programa não estará em conformidade com as especificações. Ele deve ser impresso yyyyyyyyyyyyyyyyyyyyyy...para sempre, sem novas linhas.

Dennis
fonte
1
Estamos autorizados a ler qualquer coisa após o "olá"? A questão parece proibir qualquer leitura adicional, o que pode ser problemático em idiomas como (Padrão) C, que fornecem entrada em buffer com leitura automática antecipada.
Toby Speight
Você provavelmente deve alterar a resposta aceita para a montagem, pois é 2 bytes mais curto.
Rɪᴋᴇʀ
@Riker Seria ótimo se alguém pudesse testá-lo ou pelo menos dizer que acredita que funciona primeiro.

Respostas:

2

Gelatina , 24 bytes

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

Experimente online!

Explicação:

ṫ-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.
Erik, o Outgolfer
fonte
26

C (gcc) , 81 80 76 75 72 71 70 69 bytes

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

Experimente online!

Como funciona

Este é um programa completo. Definimos uma função f para nossos propósitos. Para salvar bytes, é declarado com dois argumentos que assumem o padrão int . Esse é um comportamento indefinido, mas, na prática, n será inicializado como 1 ao executar o programa sem argumentos adicionais, c manterá os 32 bits inferiores do ponteiro no vetor de argumento

Enquanto a condição

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

detém, vamos executar o enquanto o corpo de loop:

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

Para entender completamente a condição, devemos primeiro examinar o corpo. Por enquanto, tudo o que observamos é que c=getchar()lê um único byte de STDIN (se possível) e o armazena na variável c .

A sequência de bytes hello é exibida da seguinte maneira em diferentes representações.

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

Tudo isso cai no intervalo [96, 192) , então c/96será avaliado em 1 para cada um desses bytes e em 0 para todos os caracteres ASCII restantes. Dessa forma, putchar(c)/96*c( putchar imprime e retorna seu argumento) será avaliado como c se c for `uma letra minúscula, um dos {|}~caracteres ou o caractere DEL; para todos os outros caracteres ASCII, ele será avaliado como 0 .

n é atualizado deslocando-o cinco bits para a esquerda e, em seguida, XORing o resultado com o resultado do parágrafo anterior. Como um int tem 32 bits de largura (ou seja, assumimos nesta resposta), alguns dos bits deslocados podem "cair da esquerda" (o excesso de número inteiro assinado é um comportamento indefinido, mas o gcc se comporta como a instrução x64 que gera aqui). Começando com um valor desconhecido de n , depois de atualizá-lo para todos os caracteres de hello , obtemos o seguinte resultado.

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

Observe que os 25 bits inferiores formam o número inteiro 0xb33def , que é a constante mágica na condição. Embora exista alguma sobreposição entre os bits de dois bytes adjacentes, o mapeamento de bytes abaixo de 96 a 0 garante que não haja falsos positivos.

A condição consiste em duas partes:

  • ~(getchar()) toma o NOT bit a bit do resultado da leitura (ou tentativa de leitura) de um byte de STDIN.

    Se getchar for bem-sucedido, ele retornará o valor do byte lido como um int . Como a entrada consiste inteiramente de caracteres ASCII, o byte lido pode ter apenas seus 7 bits inferiores configurados, portanto, NOT bit a bit terá seus 25 bits mais altos configurados nesse caso.

    Se o getchar falhar (não há mais entrada), ele retornará -1 e o bit a bit NOT será 0 .

  • n-0xb33def<<7subtrai a constante mágica de antes de n e , em seguida, desloca o resultado 7 unidades para a esquerda.

    Se os últimos 5 bytes de leitura foram cumprimentados , os 25 bits mais baixos de n serão iguais a 0xb33def e a subtração os zerará . Mudar a diferença resultará em 0, pois os 7 bits mais altos "cairão à esquerda".

    Por outro lado, se os últimos 5 bytes de leitura não foram hello , um dos 25 bits mais baixos da diferença será definido; após a mudança, um dos 25 bits mais altos será.

Finalmente, se getchar foi bem-sucedido e ainda não imprimimos hello , o AND bit a bit, todos os 25 bits mais altos do operando esquerdo e pelo menos um dos 25 bits mais altos do direito serão definidos. Dessa forma, &produzirá um número inteiro diferente de zero e o loop continuará.

Por outro lado, se a entrada estiver esgotada ou se já tivermos impresso hello , um dos operandos AND bit a bit será zero e o resultado também. Nesse caso, rompemos o loop e o programa termina.

Dennis
fonte
Você provavelmente deve mencionar que isso depende da entrada que está sendo codificada em ASCII, antes de se aprofundar na explicação.
perfil completo de Toby Speight
2
@TobySpeight Não acho que seja comum especificar isso. Que tipo de codificação incompatível ASCII você espera que uma resposta C use?
Dennis
EBCDIC é a codificação óbvia que não é ASCII. C não prescreve nenhuma codificação de caracteres específica (apenas que os dígitos decimais devem ser representados por valores consecutivos, em ordem).
perfil completo de Toby Speight
o programa acima será interrompido se o fluxo contiver a sequência não ascii "« úá ÷ o "1: o 111 6f 2: ÷ 246 f6 3: á 160 a0 4: ú 163 5:« 174
RosLuP
@RosLuP A especificação do desafio garante que a entrada consistirá em caracteres ASCII imprimíveis e novas linhas.
Dennis
19

Bash, 74 75 103 99 88 82 76 bytes

-10 bytes graças a @DigitalTrauma!
-11 bytes graças a @manatwork!
-6 bytes graças a @Dennis!

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

Explicação:

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

Experimente online!

betseg
fonte
2
Isso é ótimo! Eu esperava que houvesse uma resposta festiva.
13

Labirinto , 43 41 bytes

Agradecimentos ao Sp3000 por salvar 2 bytes.

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

Experimente online!

Explicação

A idéia básica é codificar os últimos cinco caracteres na base 256 em um único número inteiro. Quando um novo caractere entra, podemos "anexá-lo" multiplicando o número inteiro por 256 e adicionando o novo ponto de código. Se queremos olhar apenas para os últimos 5 caracteres, assumimos o valor módulo 256 5 = 2 40 = 1099511627776. Em seguida, podemos simplesmente verificar se esse valor é igual a 448378203247, que é o que obtemos quando tratamos os pontos de código de hellocomo base 256 dígitos.

Quanto ao código ... <...>é um pouco do idioma do labirinto. Permite gravar um loop infinito sem nenhum fluxo de controle condicional em uma única linha, economizando muitos bytes em espaços e feeds de linha. A principal condição para que isso funcione é que existem dois valores descartáveis ​​no topo da pilha quando atingimos o valor <(normalmente usamos 0s para isso, mas o valor real é arbitrário).

Obviamente, o programa precisa de alguma lógica condicional para descobrir quando terminar. Porém, é possível finalizar condicionalmente o programa dividindo-o por um valor zero quando queremos que o programa termine. A <...>construção funciona deslocando a linha inteira para a esquerda (ciclicamente) quando o IP está na extremidade esquerda e, em seguida, deslocando-a imediatamente de volta à posição. Isso significa que o código é realmente executado da direita para a esquerda. Vamos reverter:

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

Esta é uma iteração do loop que lê um caractere, termina se alcançamos o EOF, imprime o caractere, adiciona-o à nossa codificação, trunca isso para 5 caracteres, verifica a igualdade helloe se repete. Aqui está como isso funciona em detalhes (lembre-se de que o Labyrinth é baseado em pilha):

_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.
Martin Ender
fonte
8

Brainfuck, 658 bytes

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

Mais de 500 bytes estão nas constantes que eu preciso jogar um pouco.

É essencialmente uma máquina de estado, portanto, entrada infinita não é um problema.

Esta é a versão ligeiramente comentada

+
[
  >,.
  >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]
            <->>
          ]
        ]
      ]
    ]
  ]
  <<
]
jvluso
fonte
Isso parece divertido :)
Bem-vindo à Programação de quebra-cabeças e Code Golf StackExchange!
precisa saber é
1
Esse código tem vários problemas, mas o maior problema é que ele não inclui lógica para lidar com os casos ahehellobadequadamente; no meio de uma correspondência em potencial, ele verifica apenas a próxima letra helloe não procura um hrecomeço.
Mitch Schwartz
8

Bash , 73 68 66 bytes

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

Assume um diretório com nenhum ou apenas arquivos ocultos. Deve ser executado como <path/to/script>.

Experimente online!

Como funciona (desatualizado)

No início do tempo de loop, que primeiro teste se a cadeia na variável s (inicialmente vazia) é igual a olleh ( Olá para trás, OLE), e retornar 0 (fósforo) ou 1 (não um jogo) em conformidade. Embora formalmente faça parte da condição do loop, o resultado não o afetará por si só, pois apenas o último comando anterior dodetermina se a condição é válida.

Em seguida, definimos o separador de campo interno como uma string vazia (para readnão bloquear o espaço em branco), lemos os bytes brutos ( -r) de STDIN e os armazenamos c. $?é o código de saída do comando anterior, portanto, ele lê exatamente um ( -N1) byte para um não-correspondente e zero bytes ( -N0). A leitura de zero bytes, seja devido a bater no EOF ou porque -N0foi especificado, faz readcom que o código de status 1 seja encerrado; portanto, o loop while terminará; caso contrário, o corpo é executado e recomeçamos.

No corpo, primeiro imprimimos o byte que lemos e depois atualizamos s com s=$c${s::4}. Isso antecede o byte de leitura a (até) os quatro primeiros bytes em s , então s será igual a olleh depois que o hello for impresso.

Dennis
fonte
Muito bom mesmo!
8

brainfuck, 117 bytes

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

Formatado:

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

Experimente online .

Isso inicializa a fita com os caracteres hellodeslocados 107, espaçados com um valor a cada três células, acompanha os últimos cinco caracteres vistos e verifica a correspondência com cada novo caractere processado, usando uma bandeira à direita da string para acompanhar se houve uma correspondência.

Mitch Schwartz
fonte
7

Ruby , 46 60 bytes

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

Experimente online!

Lê caracteres de stdin até os últimos 5 hello, e emite a string (ou até que nenhum caractere seja deixado em stdin). Termina com erro.

Equivalente a:

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

Ou, mais não destruído:

a = ""
loop do
    q = STDIN.getc
    break if a[-5..-1] == "hello" or not q
    a += q
    print q
end
Conor O'Brien
fonte
1
acresce toda vez que um caractere é lido. Isso trava se a entrada é infinita?
precisa saber é
@betseg hm, talvez. Deixe-me ver se eu posso consertar isso
Conor O'Brien
7

Python 3, 120 116 104 bytes

Funciona com fluxos infinitos, golfe pela primeira vez, todas as dicas são apreciadas.

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

Obrigado @DJMcMayhem por salvar alguns bytes :)

R. Martin
fonte
Bem vindo ao site! c=[0,c+1]['hello'[c]==a]você deve economizar alguns bytes. Além disso, a=1é mais curto também.
DJMcMayhem
2
Você não precisa de parênteses whileno Python.
PurkkaKoodari
6

Haskell, 41 47 43 bytes

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

A preguiça de Haskell lida bem com a entrada / saída infinita.

Experimente online!

Editar: não lida com entrada finita - corrigida. Obrigado @Leo por apontar.

Editar II: @ Ørjan Johansen salvou 4 bytes. Obrigado!

nimi
fonte
2
A entrada também pode ser finita, então eu acho que você precisa para lidar com o caso quando você chegar ao final da cadeia
Leo
@ Leo: Opa, perdi totalmente. Fixo.
N
2
O primeiro guarda pode ser reduzido para |w@"hello"<-take 5l=w.
Ørjan Johansen
@ ØrjanJohansen: oh, que bom. Obrigado!
N /
6

Cubix, 94 83 82 79 63 56 bytes

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

Expandido:

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

Notas

  • O intérprete desabilita o campo de entrada quando o programa é iniciado. Como tal, um fluxo infinito de entradas é impossível. Este programa utiliza a entrada caractere por caractere, portanto, se não fosse por essa limitação, funcionaria corretamente.
  • Este programa não limpa a pilha e fica confuso muito rapidamente. Como a máquina em que isso será usado aparentemente pode fornecer fluxos de entrada infinitos, parece razoável supor que ele também tenha memória infinita.
  • Toda e qualquer ajuda no golfe é muito apreciada.

Experimente online

Você pode experimentar o programa aqui .

Explicação

Ideia geral

A idéia geral é que queremos ler um caractere e depois compará-lo com caracteres variados (primeiro h, depois e, letc.). Para acompanhar o personagem que perdemos, nós o mantemos no final da pilha. Quando precisamos, podemos facilmente trazê-lo ao topo novamente.

Loop de leitura / gravação

O loop de leitura e escrita é simplesmente a 5 ª linha. Todos os caracteres que não são usados ​​são substituídos por no-ops ( .):

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

Isso pode ser dividido em duas partes: Leitura e (escrita e verificação). A primeira parte contém as instruções até e incluindo o ponto de interrogação. A segunda parte acima é o resto da linha. Como isso ocorre, assumimos que começamos com uma pilha de[...]

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

A segunda parte (escrita e verificação) é linear novamente. A pilha começa como [next-char, ..., input]. Nós abstraímos o próximo caractere, porque isso muda mais tarde no programa.

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.

Agora, o IP será iniciado novamente no início desse loop, redefinindo o próximo caractere para o qual verificar h.

Combinando o próximo caractere

Se o IP fez uma inversão de marcha (ou seja, o caractere que lemos e imprimimos corresponde ao próximo caractere 'hello'), precisamos verificar qual caractere foi a entrada e, dependendo disso, empurrar o próximo caractere para o final da pilha. Depois disso, precisamos retornar ao loop de leitura / gravação, sem empurrar hpara a pilha, por isso precisamos de outra maneira de chegar lá.

Primeiras coisas primeiro: determine qual caractere a entrada foi. A pilha de parecido com este: [..., prev-char, input, 0].

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

Para comparar a entrada, usamos o código de caractere de hnovamente. Inicialmente, isso era porque eu realmente não sabia como lidar com isso e hé o primeiro caractere a ser verificado, mas acabou sendo bastante conveniente. Se subtrairmos o código de caractere h da entrada, obtemos -3se a entrada é e, 0se a entrada é h, 4se a entrada é le 7se a entrada é o.

Isso é útil, porque o ?comando permite separar facilmente valores negativos de valores positivos e zero. Como tal, se o IP virar à esquerda, a diferença foi negativa, a entrada foi e, então o próximo caractere deve ser um l. Se o IP continuar em linha reta, a diferença foi 0, assim como a entrada h, o próximo caractere deve ser um e. Se a entrada é uma lou umao , o IP vira à direita.

Todas as instruções executadas antes do ponto de interrogação acima são:

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

Agora, o IP muda de direção, conforme detalhado acima. Vamos examinar as diferentes possibilidades.

Entrada 'e'

Primeiro, consideraremos a entrada e, que faz com que o IP se mova para cima do ?, pois a diferença é 3. Todos os caracteres irrelevantes foram removidos do cubo.

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

Os caracteres são executados nesta ordem (excluindo alguns caracteres de fluxo de controle):

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

Agora, o IP atingiu o loop de leitura / gravação novamente.

Entrada 'h'

Se a entrada foi 'h', a diferença é 0, portanto o IP não muda de direção. Aqui está o cubo novamente, com todos os caracteres irrelevantes removidos. Como esse caminho inclui algumas no-ops, todas as no-ops pelas quais passou foram substituídas por &. O IP começa no ponto de interrogação.

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

As instruções executadas são:

'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

E agora estamos entrando no loop de leitura / gravação novamente, então terminamos.

Outras entradas

Todas as outras entradas resultam em uma diferença positiva; portanto, o IP vira à direita no ponto de interrogação. Ainda precisamos separar o le o o, e é isso que faremos a seguir.

Separando o 'l'e'o'

Lembre-se de que a diferença é 7 oe 4 le que precisamos encerrar o programa se a entrada for um o. Aqui está o cubo novamente, com as partes irrelevantes substituídas por a .e as não operações que o IP cruza foram substituídas por e comercial.

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

Discernimento entre os dois 'l' s

Então, agora sabemos que a entrada foi uma l, mas não sabemos qual l. Se for o primeiro, precisamos empurrar outro lpara o fundo da pilha, mas se for o segundo, precisamos empurrar um o. Lembre-se de que salvamos -3no final da pilha pouco antes de empurrarmos o primeiro l? Podemos usar isso para separar os dois ramos.

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

A pilha começa como [..., -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

Primeiro 'l'

Se este foi o primeiro 'l', precisamos pressionar outro 'l'. Para salvar bytes, usamos os mesmos caracteres do primeiro 'l'. Podemos simplificar a pilha para [...]. Aqui está a parte relevante do cubo, com as no-ops substituídas por e comercial.

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

As seguintes instruções são executadas:

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

Estamos prestes a inserir o loop de leitura / gravação, por isso terminamos com esse ramo.

Segundo 'l'

Se a entrada foi a segunda 'l'em 'hello', a IP virou à direita no ponto de interrogação. Mais uma vez, podemos simplificar a pilha [...]e o IP começa em ?, apontando para o sul dessa vez.

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

As instruções executadas são:

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

E o IP está prestes a entrar no loop de leitura / gravação novamente, por isso também terminamos com esse ramo.

Luke
fonte
Um esforço heróico!
5

C ++, 142 141 bytes

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

Experimente online!

Steadybox
fonte
Isso seria possível com o GCC? Não vejo #importem programas GCC C ++ ...
ckjbgames
1
@ckjbgames #importé uma extensão do GCC obsoleta.
Steadybox
1
@ckjbgames mais informações aqui: stackoverflow.com/questions/172262/…
IFreilicht
@iFreilicht Essa pergunta realmente me fez perguntar isso.
Ckjbgames
1
@ckjbgames você pode dar uma olhada na segunda resposta: stackoverflow.com/a/172264/2533467 "A importação no gcc é diferente da importação no VC ++. É uma maneira simples de incluir um cabeçalho apenas uma vez. "
IFreilicht 6/04
3

Nó, 124 bytes

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

Não assumindo que o fluxo caiba na memória disponível.

Neil
fonte
3

C #, 134 bytes

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

Experimente Online

Lê um caractere, verifica se não é -1 (EOS) e se ainda não vimos "olá", o prefixo é uma string e o escreve. Anexamos porque s[0]é muito menor do que(char)s . Isso tem um custo quadrático no comprimento da string, pois é necessário alocar e varrer toda a entrada toda vez que ele ler um caractere (isso trava após 2 GB de entrada devido a restrições no CLR, isso é permitido?)

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

Para uma versão (mais longa: 142 bytes) que não ficará sem memória e que tenha um custo constante por caractere, veja abaixo:

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

Este mantém os últimos 5 caracteres em uma string de 5 comprimentos, o que significa comparações curtas e pesquisa barata de último caractere, mas é consideravelmente mais caro para atualizar.

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;
    }
}
VisualMelon
fonte
3

PHP, 57 55 53 bytes

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

como não há arquivos infinitos, recebo informações do STDIN. Correr com-nr .

Repita a entrada, imprima o caractere atual, acrescente-o a $s, corte $sos últimos 5 caracteres. Quebrar o loop quando $sestiver hello.

Titus
fonte
3

Vim, 39 bytes

:im hello hello:se noma
:map : i

i

Experimente 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
nmjcman101
fonte
Esse é um método de entrada aceito para o Vim? Eu pensei que os programas Vim normalmente esperam que a entrada já esteja no buffer antes de começar.
Martin Ender #
Para ser sincero, não sei? Isso é verdade, mas dificilmente permite um fluxo infinito, então eu fiz dessa maneira sem realmente pensar muito sobre isso.
nmjcman101
O que acontece se houver um caractere de escape no fluxo de entrada?
dim
@dim perguntei, e o OP especificou apenas ASCII e novas linhas imprimíveis. O ESC não está incluído no
arquivo
3

PowerShell, 111 bytes

Provavelmente existe uma maneira melhor de fazer isso, mas não posso vê-lo no momento.

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

Isso lê os pressionamentos de tecla sem suprimir o eco. O caractere é adicionado a $ x, que é aparado com os últimos 5 caracteres e comparado com "olá". Isso continua até que a comparação seja verdadeira.

Nota: isso não funciona no PowerShell ISE. O ReadKey está desativado nesse ambiente.

MickyT
fonte
3

Esquema 115 bytes

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

Versão legível:

(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

Isso pega um caractere individual de stdin toda vez que o loop é marcado e marca sua posição na palavra de destino, pois ele encontra os caracteres de "hello".

Pára quando a entrada acaba ou "olá" foi visto. Nenhuma memória usada no fluxo infinito.

Pedro
fonte
Resposta legal, bem-vindo ao site!
DJMcMayhem
3

AWK, 95 bytes

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

Há duas coisas que aprendi aqui:
1) Para dividir registros entre caracteres, use RS="(.)"e depois RTdeve ser usado em vez de $1
2) ORSé usado por printe tem como padrão "\n"
3) Não posso contar até 2 e usar printfé "mais barato" do que atribuir ORSe usandoprint

Exemplo de uso: coloque o código em FILE

awk -f FILE some_data_file

ou

some process | awk -f FILE

O código foi testado usando a yes | ...sugestão de Dennis e vi muitos e muitos ys.

Para sua informação, você pode fazer a atribuição de RS como uma opção e retirá-la do BEGINbloco via:

awk -v RS='(.)'
Robert Benson
fonte
Solução realmente complicada! (Talvez porque é sexta-feira à tarde, mas acho que é boa entrada para o desafio ofuscado também.) Embora eu iria tentar uma abordagem mais awkish: BEGIN{RS="(.)"}{printf RT}"olleh"==a=RT substr(a,1,4){exit}.
manatwork
Curiosamente, eu tenho quase exatamente a resposta pronta para enviar uma hora atrás ... e esqueci de enviá-lo. : p
Robert Benson
3

Python 3 (Linux), 73 72 bytes

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

Graças a @MitchSchwartz por jogar fora um byte!

Experimente online!

Dennis
fonte
Eu não entendo Como a condição para whileavaliar adequadamente? Parece que você está comparando um booleano a uma string vazia.
IFreilicht 6/04
1
s[print(end=c):4]salva um byte
Mitch Schwartz
1
O @iFreilicht Python analisa condicionais encadeados como faria em matemática ( a <b <c , por exemplo). A condição é uma abreviação de 'olleh'!=s and s>''and''<c). O teste do meio não é necessário, mas encadeá-los é mais curto que o simples 'olleh'!=s and''<c.
7897 Dennis
@MitchSchwartz Isso é verdade. Obrigado!
7897 Dennis
3

Código de máquina 8086, 22 bytes

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

Código de montagem equivalente:

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"
user5434231
fonte
Como funciona?
1
Eu adicionei o código de montagem equivalente. Basicamente, ele conta com um syscall do DOS muito útil, que lê um byte de stdin e o repete em stdout ao mesmo tempo. O 8086 também possui uma instrução de comparação de string de byte único, que é útil aqui.
user5434231
2

Pitão, 49 47 bytes

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

Pyth não é muito bom em aceitar um único caractere de entrada. Tudo em$__import__("sys").stdin.read(1) é simplesmente fazer isso. Além disso, isso significa que isso é executado apenas offline.

Tudo o resto é curto ...

O programa é um loop while sem corpo. Dentro da condição, o programa lê um caractere, o imprime novamente e acrescenta esse caractere aok (que é inicialmente a string vazia), apara todos os caracteres k, exceto os últimos 5, exceto os últimos 5 caracteres e verifica se o resultado não está "hello".

32 caracteres estão recebendo um byte de entrada, 15 caracteres fazem o resto.

Testado no Linux, funciona mesmo sem nova linha, entrada infinita, etc.

isaacg
fonte
2

Lua, 68 64 bytes

l=""while l~="hello"do c=io.read(1)io.write(c)l=l:sub(-4)..c end
Blab
fonte
1
Altere a fatia para l:sub(-4), então você pode reduzir a inicialização de l="".
manatwork
@manatwork Isso é legal. Obrigado pela dica.
quer
2

Ruby, 59 49 48 43 bytes

Agora livre de discursos, mais curto e sem vazamento de memória.

s=''
s=$>.putc$<.getc+s[0,4]until'olleh'==s

Economizou 5 bytes ao se livrar de alguns parênteses e espaço graças a Dennis

daniero
fonte
Vamos continuar esta discussão no chat .
Daniero 4/04
1

Röda , 49 47 bytes

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

Experimente online!

Essa é uma função anônima que lê caracteres do fluxo de entrada e os envia até que "hello" seja encontrado. Ele usa a matriz apara rastrear os últimos caracteres.

Ele gera algum lixo para STDERR, mas entendi que é permitido .

Explicação:

{
    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. */
}
fergusq
fonte
Onde está a documentação do Roda?
precisa saber é o seguinte
@ckjbgames Aqui. Eu uso a versão mais recente 0.12, que está em seu próprio ramo no Github.
Fergusq 04/04
1

Java 7, 122 118 124 123 150 141 bytes

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

Agora para quando o final do fluxo é atingido. Agora lida com entrada infinita sem ficar sem memória.

Cutucar
fonte
Aposto que isso não suporta entrada infinita.
Titus
@Titus corrigido ...
Poke
Fiz voto negativo sem ver writesendo usado em vez de print. Não posso desfazer meu voto negativo, desculpe por isso :(
Olivier Grégoire
1

Ruby, 51 bytes

x="";$><<x[-1]while/hello./!~x=x[/.{0,5}$/]+$<.getc
  • Não espera novas linhas
  • Funciona com entrada infinita
GB
fonte
1

AHK , 116 bytes

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

Não há nada inteligente ou mágico lá, realmente. A variável %1%é o primeiro argumento passado e deve ser um caminho de arquivo com o fluxo. O arquivo deve ser salvo à medida que for atualizado, mas o código será lido até o fim, mesmo se ele se expandir após o início da leitura.

Engenheiro Toast
fonte
1

Mathematica, 107 bytes

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

A saída se torna um campo em que o usuário pode digitar infinitamente texto (incluindo novas linhas) até que os últimos 5 caracteres sejam iguais "hello"; nesse ponto, ele sai.

numbermaniac
fonte
1

brainfuck , 281 bytes

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

Eu não sei por que, mas eu senti que foder o cérebro era a coisa certa a fazer isso. Não requer memória infinita e pode produzir para sempre.

Explicado

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
]

Experimente online!

ATaco
fonte
Eu ia fazê-lo assim, mas então eu percebi que este saídas do zero bytes infinitly para a entrada que não contém "Olá": tio.run/nexus/...
KarlKastor
Isso também falha ahehellob.
Mitch Schwartz