!Inserir! ! n! b! e! t! w! e! e! n!

24

Postado aqui .

Este desafio é altamente "destilado" desta questão. Agradecimentos especiais a @Akababa!

Nesta tarefa, você deve inserir um ponto de exclamação no início da sequência e após cada caractere.

Regras

  • Sempre haverá uma entrada de sequência não vazia. A entrada também não conterá guias. Você pode assumir que a entrada contém apenas caracteres imprimíveis ASCII não estendidos e novas linhas.
  • A entrada não conterá novas linhas à direita, desde que seu idioma não consiga detectar uma nova linha.
  • Este é um concurso de ; a resposta mais curta deve ganhar.

Exemplos

  • 4 novas linhas resultam em 5 pontos de exclamação delimitados por novas linhas. É muito difícil colocar isso como um texto Markdown, portanto, isso é declarado.
1 2 3 4 5 6
129591 129012 129127 129582

0 0

Saídas

! 1! 2! ! 3! ! 4! ! 5! 6!
! 1! 2! 9! 5! 9! 1! ! 1! 2! 9! 0! 1! 2! ! 1! 2! 9! 1! 2! 7! ! 1! 2! 9! 5! 8! 2!
!
0!
asd afjoK também: e
kPrLd
    fOJOE;
    KFO
KFkepjgop sgpaoj faj

Saídas

! a! s! d! ! a! f! j! o! K! ! a! k!:! e!
! k! P! r! L! d!
! ! ! ! ! f! O! J! O! E!;!
! ! ! ! K! F! O!
! K! F! K! E! P! J! G! O! P! ! s! g! p! a! o! j! ! ! ! f! a! j!

Um caso de teste básico com apenas um caractere:

uma

Saídas

!uma!

(Preenchimento automático! Brincadeirinha, não existe isso.) Contém pontos de exclamação:

!!
!!
!!
!!
!!

Saídas:

!!!!!
!!!!!
!!!!!
!!!!!
!!!!!
UMA
fonte
7
Realmente não entendo o voto negativo - este é um desafio claro e bem escrito. Re: ser uma duplicata - não é (precedendo '!' Faz uma grande diferença), e eu não acredito que alguém tenha sugerido isso (sem votos próximos).
Jonathan Allan
11
se um idioma não pode distinguir entre a\ne a, podemos exigir que não haja novas linhas à direita?
Giuseppe
13
Os votos negativos são inseridos entre todos os votos positivos, exatamente como o desafio descreve.
A
2
Isso está morto.
V. Courtois

Respostas:

33

QuadR , 1 byte

Agradecimentos a A__ por reduzir pela metade a contagem de bytes!

!

Experimente online!

Não substitui nada por !

Adão
fonte
12

Python 3 , 27 bytes

lambda s:f"!{'!'.join(s)}!"

Experimente online!

Honestamente, espero que alguém possa me mostrar uma maneira legal de fazer isso com uma contagem menor de bytes.

Restabelecer Monica
fonte
Isso não lida com o caso de linha vazia corretamente
flocos
@flakes Como assim? Se você quer dizer uma string vazia: não precisamos manipular uma string vazia (e, independentemente disso, essa saída é !!nesse caso, que é o que faz sentido para mim). Se você quer dizer a string \n: sim, desde que a saída correta seja !\n!.
Jonathan Allan
3
@JAD Tanto quanto posso ver, ele não possui uma string vazia nos exemplos. Não apenas isso, mas a primeira regra afirma literalmente "sempre haverá uma entrada de string não vazia".
Restabelecer Monica
11
Ah, eu estava incorreto. O primeiro exemplo tem uma linha vazia no meio da entrada. Mas esta resposta tratará de colocar o ponto de exclamação no meio disso !\n!\n!. bom trabalho.
flakes
11
codegolf.stackexchange.com/questions/190223/insert-nbetween/… como você estava dizendo para mostrar uma maneira mais curta
Re-U10-Forward - Reinstate Monica
10

Haskell, 18 bytes

('!':).(>>=(:"!"))

-1 byte graças a @nimi

Experimente online!

Leo Tenenbaum
fonte
2
('!':).salva um byte.
nimi 18/08
8

JavaScript (ES6), 19 bytes

Recebe a entrada como uma matriz de caracteres.

s=>`!${s.join`!`}!`

Experimente online!


JavaScript (ES6),  23  20 bytes

Guardado 3 bytes graças a @ShieruAsakoto

Recebe a entrada como uma sequência.

s=>[,...s,,].join`!`

Experimente online!


JavaScript (ES6), 22 bytes

Sugerida por @tjjfvi

Recebe a entrada como uma sequência.

s=>s.replace(/|/g,"!")

Experimente online!

Arnauld
fonte
@tjjfvi Nifty one!
Arnauld
5
Eu tenho 20 para o seu 23:s=>[,...s,,].join`!`
Shieru Asakoto
7

R , 25 bytes

function(x)gsub("","!",x)

Experimente online!

Uma função que aceita e retorna um vetor de caractere.

Nick Kennedy
fonte
Pode barbear 3 bytes alternando o formulário da função para scan(,''), como tio.run/##K/r/P724NElDSUlHSVFJpzg5MU9DR11dU/O/…
Sumner18
@ Sumner18 obrigado. Comecei com isso, mas divide a entrada em espaços.
Nick Kennedy
11
@ Sumner18 O desafio pede para lidar com a entrada com novas linhas, o que não pode ser feito scan(mas com a solução de Nick, pelo menos se você exibir a saída cat).
Robin Ryder
7

Código de máquina 8086, formato .COM (MS-DOS 2+), 32 bytes

(-1 dependendo do emulador: veja abaixo)

Para obter melhores resultados, redirecione a entrada padrão de um arquivo, pois a digitação fornece uma aparência estranha devido a nenhum buffer; Além disso, as novas linhas parecem um pouco estranhas porque são armazenadas como CR LFe a CRparte atrapalha a saída.

Esse programa se comporta bem em uma emulação real do MS-DOS (por exemplo, PCjs), mas o DOSBox parecia ter problemas com o Ctrl + Z EOF (consulte os comentários na lista de montagem), portanto NÃO tente inserir entradas usando o console no DOSBox, a menos que você adicione o cheque extra!

BB 01 00 53 59 BA 0B 01 B4 40 CD 21 4A 4B B4 3F CD 21 85 C0 74 09 B4 40 43 41 CD 21 49 EB EE C3

Alguns bits interessantes:

  • Economizei algum espaço de dados reutilizando a memória que já havia sido executada (o 21H no INT 21Hpassa a ser !)

  • Eu quase consegui usar um truque interessante que encontrei na página "O poder oculto das instruções do BCD" que me permitiria usar em AAAvez de um padrão TESTpara comparar ALcom 0, economizando um byte. Infelizmente, isso não está totalmente documentado, por isso não pude confiar nele: por exemplo, o PCjs não ajusta nada além das bandeiras carry e auxiliar. :-(

Código de montagem (modo ideal TASM):

IDEAL
MODEL   TINY

CODESEG
ORG 100H

;; DOSBox (tested with 0.74-2) didn't seem to handle Ctrl-Z as EOF
;; so uncomment the ";;" lines to run it there.
MAIN:
    MOV     BX,1
    PUSH    BX
    POP     CX
    MOV     DX,OFFSET MAIN_1+1  ; The 21H in INT 21H
    MOV     AH,40H
MAIN_1:
    INT     21H
    DEC     DX
    ;;PUSH  DX
    ;;POP   SI
IO_LOOP:
    DEC     BX
    MOV     AH,3FH
    INT     21H
    ;;; This should work on an non-emulated PC. 
    ;;;AAA      ; AL=0?
    TEST    AX,AX
    JZ      DONE
    ;;CMP   [BYTE PTR SI],1AH
    ;;JZ    DONE
    MOV     AH,40H
    INC     BX
    INC     CX
    INT     21H
    DEC     CX
    JMP     IO_LOOP
DONE:
    RET
ENDS
END MAIN
ErikF
fonte
7

brainfuck , 24 22 bytes

-2 bytes graças ao JoKing.

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

Experimente online!

Krzysztof Szewczyk
fonte
@JoKing obrigado, eu atualizei minha resposta.
Krzysztof Szewczyk
caramba, isso é foda
Cruncher 19/08/19
6

Pepe , 47 bytes

REREEeRErEErREeeEeeeeEREEeeREEeereeREEEEeeEReee

Experimente online!

Explicação:

REREEeRE # Push 0,then input (str),then 0 -> (R)
         # The zeroes are pushed to correct the inserting
rEE # Begin loop labelled 0 -> (r)
  rREeeEeeeeE # Push "!" -> (R)
              # r flag inserts it instead of pushing
  REEeeREEee # Move pointer pos 2 steps forward -> (R)
ree # Loop while (R) != 0
REEEEeeE # Remove characters of (R) that are in stack of (r)
         # Removes the 0 in (R)
Reee # Output (R)
Indefinido
fonte
Como você escreve esse código? Existe algum conversor de código que você usa? Isso parece uma loucura para tentar escrever
Cruncher
11
@Cruncher 1) Eu uso isso como meu guia. 2) Não, eu não uso um conversor de código, apenas uso o guia para escrever o código.
u_ndefined 20/08
6

Labirinto ,  19 11 10  9 bytes

33
..
",@

Experimente online!

Quão?

Entramos no labirinto no canto superior esquerdo, com uma pilha infinita de zeros ...

                         I / O    stack
                                  0,0,0,...
3 - pop * 10 + 3                  3,0,0,0,...
  - 2 neighbours, forward
3 - pop * 10 + 3                  33,0,0,0,...
  - 2 neighbours, forward
. - pop & print chr          !    0,0,0,...
  - T junction from the side
  -   TOS==0, forward
, - read chr or -1       L        76,0,0,0,...   or   -1,0,0,0
  - T junction from the base
  -   if TOS > 0 right:
" -     no-op                     76,0,0,0,...
  -     2 neighbours, forward
. -     pop & print chr      L    0,0,0,...
  -     T junction from the side
  -       TOS==0, forward
3 -       ...back to the start
  -   elif TOS == -1 left:
@ -     exit                                          we're out!


  * right, but on the first occasion (from above) we hit the wall and turn
    around, so that's like a left

Felizmente, não precisamos lidar com imprimíveis, caso contrário, o primeiro byte zero nos transformaria e causaria ,estragos.

Jonathan Allan
fonte
5

sed , 12 bytes

s/\b\|\B/!/g

Experimente online!

-3 bytes graças ao Cows Quack

Jonah
fonte
Na verdade, o código Sed tem apenas 15 caracteres: Experimente online! .
manatwork
Ótimo, obrigado. Eu não estava claro como isso funcionava ...
Jonah
11
s/\b\|\B/!/gtambém funciona para 12 bytes
Kritixi Lithos
@Cowsquack obrigado. Atualizada.
Jonah
4

Zsh , 32 bytes

for c ('' ${(s::)1})echo -nE $c!

Experimente online!

(s::)divide em caracteres, ''adiciona um elemento vazio ao início e echo -nE $c!ecoa cada um seguido por um !.

GammaFunction
fonte
4

Perl 5 -p0, 17 6 bytes

s,,!,g

Experimente online!

Minha resposta original foi -pe $_='!'.s,.,$&!,gr. Agradecemos a @Nahuel Fouilleul por cortar 11 bytes e a @Grimy pela -p0dica.

Kjetil S.
fonte
2
6 bytes
Nahuel Fouilleul
11
@NahuelFouilleul -lpfornece uma saída incorreta para o \n\n\n\ncaso de teste (retorna 4 separados por nova linha em !vez dos 5 especificados). -p0funciona corretamente.
Grimmy 19/08
4

6502, 12 bytes (13 bytes se Apple II)

6502

O código da máquina pressupõe que um par de locais de zero páginas esteja conectado ao hardware de entrada de caracteres ($ FE) e saída (FF). Muitos sistemas baseados no 6502 facilitam a E / S dessa maneira, embora o endereço de E / S normalmente não esteja na página zero.

Para simplificar, usei o Py65 , um simulador de sistema de microcomputador 6502 escrito em Python.

Aqui está um despejo de memória do Py65. Você pode carregar o código a seguir em qualquer lugar na página zero, para que não se sobreponha a $ FE e $ FF.

       PC  AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110010
.mem 0:b
0000:  a9  21  85  ff  a5  fe  f0  fc  85  ff  d0  f4

Executando em uma janela de comando do Windows, você pode colar (Ctrl + V) qualquer texto que desejar ou simplesmente digitar. Se estiver digitando, pressione Ctrl + J para obter uma nova linha (o mesmo caractere ASCII). Pressione Ctrl + C para interromper o processador e retornar ao prompt de comando Py65.

Naturalmente, o código de montagem é mais fácil de ler.

       PC  AC XR YR SP NV-BDIZC
6502: 0000 00 00 00 ff 00110010
.d 00:0b
$0000  a9 21     LDA #$21
$0002  85 ff     STA $ff
$0004  a5 fe     LDA $fe
$0006  f0 fc     BEQ $0004
$0008  85 ff     STA $ff
$000a  d0 f4     BNE $0000

Para maior clareza, aqui está o código de montagem no formato CBA65 .

; ASSEMBLE:
; cba65 bangit
;
; LOAD/RUN
; python3 py65/monitor.py -i 00fe -o 00ff -l bangit.bin
; goto 0000

        .FILES  BIN=256

; I/O LOCATIONS
GETC    .EQU    $FE             ; (1) MOVING PY65'S GETC TO ZP SHAVES 1 BYTE
PUTC    .EQU    $FF             ; (1) MOVING PY65'S PUTC TO ZP SHAVES 2 BYTES

        .ORG    $0000

VROOM   LDA     #'!'
        STA     PUTC
VROOM2  LDA     GETC
        BEQ     VROOM2
        STA     PUTC
        BNE     VROOM

        .END

Apple II

O código acima assume que um nulo indica que não há entrada; portanto, continua a pesquisa até que um valor não nulo seja retornado.

Para comparação, o Apple I e o Apple II sinalizam a disponibilidade de um novo caractere, definindo o bit 7 do endereço de E / S do teclado, que precisa ser limpo após a busca do caractere. Nesses sistemas, a E / S de caracteres geralmente é executada chamando as rotinas do monitor do sistema em vez de acessar o hardware diretamente.

Ao chamar RDKEY ($ FD0C) e COUT ($ FDED), o equivalente do Apple II acima pode ser codificado em 13 bytes e é executável em qualquer lugar da RAM. Aqui está o código que eu corri em um emulador da Apple // e, a2ix no Android 9.

Pressionar Return tem o mesmo efeito que uma nova linha.

*300L

0300-   A9 A1       LDA   #$A1
0302-   20 ED FD    JSR   $FDED
0305-   20 0C FD    JSR   $FD0C
0308-   20 ED FD    JSR   $FDED
030B-   F0 F3       BEQ   $0300

Você notou que, em vez do valor ASCII normal # $ 21 para o ponto de exclamação, # $ A1 é usado? Isso ocorre porque o envio de valores ASCII padrão para COUT faz com que sejam exibidos no "modo inverso", em preto e branco. A exibição de ASCII em branco normal em preto requer a adição de $ 80 ao valor do caractere no acumulador antes de chamar COUT. Como RDKEY retorna caracteres com o conjunto de hi-bits, os programas de montagem geralmente limpam o bit do caractere para obter seu valor ASCII antes de usá-lo.

lee
fonte
11
Bem vindo ao site! :)
Rahul Bharadwaj
Obrigado, @Rahul!
lee
4

Bash , 36 bytes

while read -n1 c;do printf \!$c;done

Experimente online!

Isso conta com a nova linha encerrando a entrada pela última! marca.

spuck
fonte
Bem vinda! Por favor, considere adicionar uma explicação ou link a um intérprete ou algo assim, porque as respostas somente de código são automaticamente sinalizadas como de baixa qualidade.
mbomb007 19/08
@ mbomb007, obrigado pelo ponteiro.
spuck 19/08
11
Infelizmente, isso não adiciona um !no final da entrada.
Kritixi Lithos
@ Cowquack: no meu terminal, a nova linha que termina a entrada recebe o! adicionado. No tio.run, a entrada precisa ser finalizada com um retorno de carro. Atualizei o link do Try it Online para refletir isso.
spuck 20/08
4

MarioLANG , 95 94 90 89 69 bytes

++++++
======< >)
>+++++++",+[
=======<.==<
>+++++++!(.-
========#===

Experimente online!

A primeira vez que experimentei o MarioLANG, foi muito divertido!

Agradecimentos a Jo King por -20 bytes

Explicação:

Assim, como o nome indica, MarioLANG é feito para executar como um jogo de Super Mario Bros. Opera de maneira semelhante ao BF, com memória disposta em uma fita de células. Existem operadores para incrementar, diminuir, imprimir (como ascii ou numéricos) e ler na célula de memória atual e operadores para mover para a esquerda ou direita ao longo da fita.

Mario (o ponteiro de instruções) sempre começa na célula superior esquerda do programa, com a direção do movimento pretendida definida à direita. Se Mario não tiver um objeto semelhante a um piso embaixo dele (=, "ou #), ele cairá até atingir um objeto semelhante a um piso. Se Mario deixar o espaço do programa, o programa será encerrado devido ao Game Over :(

Este programa específico pode basicamente ser dividido em duas partes: a instalação e o loop.

   Setup                          Loop
-----------------------------------------------
                       |
++++++                 |          
======<                |          >)
>+++++++               |          ",+[
=======<               |          .==<
>+++++++               |          !(.-
========               |          #===

Na seção Configuração, estamos simplesmente incrementando a primeira célula de memória até atingir 33 - o valor ASCII para "!". Bastante fácil; se isso pode ser praticado, é puramente uma questão de forma. Mario começa no canto superior esquerdo, pega 10 moedas, começa a cair ao pegar o 11º, muda de direção e depois repete. Ele pega as últimas 11 moedas sem mudar de direção; ele termina a seção de configuração no canto inferior direito "+".

Na seção de loop, Mario começa alcançando um elevador. O "!" O operador o faz cessar o movimento, para que ele permaneça no elevador. No caminho, ele imprime o caractere ASCII correspondente no valor da célula de memória atual (este é sempre 33, "!") E depois muda para a próxima célula na memória. Mario chega ao topo e define sua direção para a direita. Ele cai e lê um caractere da entrada como seu valor ASCII (ou -1 se nenhum caractere). Aumentamos porque a única medida de controle no MarioLANG é pular uma instrução se a célula de memória atual tiver um valor 0. Se isso acontecer, pularemos a alteração da direção de Mario, para que ele ande do próximo andar até a sua desgraça. Caso contrário, definimos a direção para a esquerda; andar parado do piso abaixo diminui a célula atual de volta ao seu valor anterior,


Versão anterior (89 bytes):

+++++++++++>,
==========@"+
+++++++++++)[
@==========.==<
+++++++++++!(.-
===========#===
Restabelecer Monica
fonte
62 bytes usando um loop de multiplicação em vez de apenas um contador
Jo King
Ok, agora isso é legal. Vou atualizar assim que tiver tempo para refazer a explicação, muito obrigado!
Restabelecer Monica
11
Aha! 60 bytes multiplicando 5 * 6 + 3 em vez de 8 * 4 + 1
Jo King
Cara, eu sei que não é exatamente o seu primeiro rodeio, mas isso é realmente impressionante. xD
Restabelecer Monica
Na verdade, esta é a minha primeira vez jogando MarioLANG. Eu só tenho alguma experiência com brainfuck, bem como outras linguagens 2D
Jo King
4

Perl 6 , 16 11 bytes

{S:g/<(/!/}

Experimente online!

Substitui todas as correspondências de largura zero por pontos de exclamação. Regexes nulas não são permitidas; portanto, usamos um marcador de captura para capturar nada.

Brincadeira
fonte
3

05AB1E , 4 bytes

€'!Ć

E / S como uma lista de caracteres.

Experimente online.

Explicação:

'!  '# Prepend a "!"-item before each character in the (implicit) input-list
   Ć  # Enclose (append the first character of the list at the end of it)
      # (after which the result is output implicitly)
Kevin Cruijssen
fonte
3

Triangular , 15 13 bytes

B\3;#*~.,</@<

Experimente online!

-2 bytes depois de lembrar que o Triangular possui um operador de parada condicional.

Acredito que seja o mais curto possível. Triangular faz tem operadores condicionais direção de mudança, mas, infelizmente, funcionam de forma diferente do que os outros condicionais. Enquanto todos os outros verificam se ToS <= 0, as condicionais de mudança de direção verificam ToS! = 0. Se não fosse esse o caso, teríamos 10 bytes no formato de Bq3~#*/@<<.

Ungolfed:

    B
   \ 3
  ; # *
 ~ . , <
/ @ <
----------------------------------------------------
B3*              - Push 11 and 3, then pop both and push their product.
    <,<          - Change directions 3 times (to save 2 bytes on last line)
        @/       - Print Top of Stack value as a character, do not pop
          ~;\    - Push a character from input to ToS. Halt if ToS <= 0. Change Direction.
              #  - Print ToS as a character and pop

Versão anterior (15 bytes):

B.3\.*#).(/?~@<
Restabelecer Monica
fonte
3

SimpleTemplate , 23 bytes

Esta é uma linguagem que eu escrevi, e deveria ser para modelos, mas bem.

!{@eachargv.0}{@echo_}!

Deve ser quase auto-explicativo, depois de ver o código não-destruído:

!{@each argv.0 as char} {@echo char}!{@/}

E uma explicação:

  • !- Imprime o !caractere literal
  • {@each argv.0 as char}- Faz um loop em todos os caracteres, com o valor definido para a variável char( opcional , a variável padrão é _).
    argv.0é o primeiro parâmetro passado para o render()método do compilador.
  • {@echo char}!- gera a charvariável e um !caractere literal .
    Para a versão golfed, a variável padrão_ é usada.
  • {@/}- fecha o loop ( opcional )

Solução Pure SimpleTemplate :

{@fn x}!{@eachargv.0}{@echo_}!{@/}{@/}

Cria uma função xque gera o mesmo resultado.

Você pode usá-lo assim:

{@call x "this is an example"}

Você pode tentar tudo isso em: http://sandbox.onlinephpfunctions.com/code/f6baff8d411fc8227ece81eccf05b6e7d3586bfa

Na linha 908, você pode usar as variáveis $golfed, $ungolfede $fnpara testar todas as versões.



No entanto, se for permitido usar uma matriz de caracteres, o código será simplificado (20 bytes):

!{@echoj"!" argv.0}!

E não destruído:

!{@echo separator "!" argv.0}!

Basicamente, gera todos os itens da matriz, unidos por "!", cercados por literal !.
Devido a limitações na classe do compilador, o espaço é obrigatório (na versão golfed).

Esse código também é extremamente difícil de usar no SimpleTemplate puro (usando a função como exemplo):

{@fn x}!{@echoj"!" argv.0}!{@/}

{@// alternative: @call str_split into a "a char array"}
{@set a "a", " ", "c", "h", "a", "r", " ", "a", "r", "r", "a", "y"}

{@call x a}

O @callpode chamar uma função que existe no PHP, o que significa que não é uma solução pura do SimpleTemplate .

Ismael Miguel
fonte
3

Ruby , 17 16 bytes

->s{s.gsub'',?!}

Experimente online!

Agradecemos o valor de tinta por -1 byte

GB
fonte
Retire o espaço depois gsub.
Value Ink
2

Gema , 11 caracteres

\A=\!
?=?\!

Infelizmente, !inicia um comentário no Gema, portanto, deve ser evitado.

Exemplo de execução:

bash-5.0$ echo -ne '1 2 3 4 5 6\n129591 129012 129127 129582\n\n0' | gema '\A=\!;?=?\!'
!1! !2! !3! !4! !5! !6!
!1!2!9!5!9!1! !1!2!9!0!1!2! !1!2!9!1!2!7! !1!2!9!5!8!2!
!
!0!

Experimente online!

homem a trabalhar
fonte
2

Gelatina , 5 bytes

Ż”!ṁż

Um programa completo que aceita uma string, que imprime o resultado.

Experimente online!

Quão?

Ż”!ṁż - Main Link: list of characters, s   e.g. "abc"
 ”!   - character '!'                           '!'
   ṁ  - mould like:
Ż     -   s with a zero prepended              "!!!!"
    ż - zip together with s                    ["!a","!b","!c",'!']
      - implicit (smashing) print              !a!b!c!
Jonathan Allan
fonte
2

Japonês , 4 bytes

rP'!

Tente

r      Replace
 P     all empty strings "" with
  '!   An exclamation mark (If '!' wasn't a special character in Japt I could remove the quote)
Forma de Ignorância
fonte
Você só seria capaz de abandonar o número 'se a substituição fosse um número.
Shaggy
2

Japonês , 4 bytes

rP'!

Tente

Japonês -P , 7 bytes

Infelizmente, !é um caractere reservado, necessitando de aspas.

ï'! i'!

Tente

Não há muito a explicar: ïé um produto cartesiano e iprecede.

Shaggy
fonte