Exibir um xkcd

36

O xkcd é o webcomic favorito de todos, e você estará escrevendo um programa que trará um pouco mais de humor para todos nós.
Seu objetivo neste desafio é escrever um programa que terá um número como entrada e exibirá o xkcd e seu texto do título (texto do mouse).

Entrada

Seu programa pegará um número inteiro positivo como entrada (não necessariamente um para o qual exista um quadrinho válido) e exibirá o xkcd: por exemplo, uma entrada de 1500 deve exibir o "Mapa de cabeça para baixo" do quadrinho em xkcd.com/1500, e, em seguida, imprima o título do texto no console ou exiba-o com a imagem.

Devido à proximidade do canal, há muito que existe tensão entre a Coréia do Norte e o Reino Unido da Grã-Bretanha e sul da Irlanda. Due to their proximity across the channel, there's long been tension between North Korea and the United Kingdom of Great Britain and Southern Ireland.

Caso de teste 2, para n = 859:

Cérebros à parte, pergunto-me quantos scripts mal escritos para análise do xkcd.com serão quebrados nesse título (ou ;; "'' {<< ['este texto do mouse". "

Brains aside, I wonder how many poorly-written xkcd.com-parsing scripts will break on this title (or ;;"''{<<[' this mouseover text."

Seu programa também deve poder funcionar sem nenhuma entrada e executar a mesma tarefa para o xkcd mais recente encontrado em xkcd.com, e sempre deve exibir o mais recente, mesmo quando um novo é iniciado.

Você não precisa obter a imagem diretamente do xkcd.com, pode usar outro banco de dados, desde que esteja atualizado e já exista antes que esse desafio ocorra. Os encurtadores de URL, ou seja, URLs com nenhum outro objetivo além de redirecionar para outro lugar, não são permitidos.

Você pode exibir a imagem da maneira que escolher, inclusive em um navegador. No entanto, você não pode exibir diretamente parte de outra página em um iframe ou similar. ESCLARECIMENTO: você não pode abrir uma página da web preexistente, se desejar usar o navegador, precisará criar uma nova página . Você também deve realmente exibir uma imagem - não é permitido produzir um arquivo de imagem.

Você pode lidar com o caso de que não há uma imagem para um determinado quadrinho (por exemplo, é interativo ou foi passado um número maior do que a quantidade de quadrinhos que foram lançados) da maneira que você desejar, incluindo uma exceção , ou imprimir uma sequência de pelo menos um caractere, desde que de alguma forma signifique ao usuário que não existe uma imagem para essa entrada.

Você só pode exibir uma imagem e exibir o texto do título ou enviar uma mensagem de erro para um quadrinho inválido. Outra saída não é permitida.

Este é um desafio de , portanto, o menor número de bytes vence.

Pavel
fonte
1
@LukeFarritor Você só pode exibir a imagem e gerar o texto do título ou gerar alguma forma de mensagem de erro para um quadrinho inválido.
Pavel
9
Se o tamanho da amostra é 1, import antigravityem Python;)
Wayne Werner
15
Fato engraçado n=404 xkcd.com/404 é uma página 404.
Magic Octopus Urn
11
xkcd is everyone's favorite webcomic [Citação necessário ]
Sanchises 27/10/16
11
Caso de teste: 859
betseg 27/10/16

Respostas:

13

Perl + ondulação + feh, 86 84 75 bytes

`curl xkcd.com/$_/`=~/<img src="(.*)" title="(.*?)"/;$_=$2;`feh "http:$1"`

Requer a -ptroca. Eu expliquei isso na contagem de bytes.

um spaghetto
fonte
@ Matt Funcionou em todos os quadrinhos que tentei. Combina apenas imagens com texto alternativo.
a spaghetto
Você pode não precisar das aspas ao redor do atributo src.
Conor O'Brien
Acho que você não precisa do ?grupo do primeiro jogo. Você pode usar -pe, em $_=$2vez de print$2, mas o texto do título é impresso somente após o fechamento do feh. Não tenho certeza se isso é válido.
m-Chrzan
@ m-chrzan Sim, parece que eu posso largar o quantificador relutante lá, obrigado. Pensei em usar, -pmas não tinha certeza de como seria o OP.
a spaghetto
@ ConorO'Brien Infelizmente Randall observa boas práticas de codificação HTML ... e capturar as aspas não cita os argumentos devido a como os backticks funcionam no Perl.
um spaghetto
9

PowerShell v3 + 110 99 107 103 bytes

iwr($x=((iwr "xkcd.com/$args").images|?{$_.title})).src.Trim("/") -outf x.jpg;if($x){ii x.jpg;$x.title}

Agradecemos a Timmy por ajudar a economizar alguns bytes usando atribuições em linha.

Se nenhum argumento for passado, $argsserá nulo e ele obterá o quadrinho atual. Faça o download da imagem, combinando a imagem com o texto alternativo, em um arquivo no diretório em execução atual do script. Em seguida, exiba-o com o visualizador padrão de jpg. O texto alternativo é exibido no console. iwré um apelido paraInvoke-WebRequest

Se o número passado (ou qualquer entrada inválida) não corresponder, o processo falhará com pelo menos um erro 404.

iwr(                                  # Request the comic image from XKCD
  $x=((iwr "xkcd.com/$args").images|  # Primary search to locate either the current image
                                      # or one matching an argument passed
     ?{$_.title}))                    # Find the image with alt text
        .src.Trim("/")                # Using the images associated link and strip the leading slashes
  -outf x.jpg                         # Output the image to the directory local to where the script was run
if($x){                               # Test if the image acquisition was successful
    ii x.jpg                          # Open the picture in with the default jpg viewer
    $x.title                          # Display alt text to console
}                                     # I'm a closing bracket.
Matt
fonte
Apenas tenho o meu comentário privilégio neste sub agora, confira a minha resposta muito semelhante
colsw
@ConnorLSW Ótima abordagem em sua resposta. Coisas para pensar para a próxima vez.
Matt
8

AutoIt , 440 bytes

Sim, é longo, mas é estável.

#include<IE.au3>
#include<GDIPlus.au3>
Func _($0='')
_GDIPlus_Startup()
$1=_IECreate('xkcd.com/'&$0)
For $3 In $1.document.images
ExitLoop $3.title<>''
Next
$4=_GDIPlus_BitmapCreateFromMemory(InetRead($3.src),1)
$6=_GDIPlus_ImageGetDimension(_GDIPlus_BitmapCreateFromHBITMAP($4))
GUICreate(ToolTip($3.title),$6[0],$6[1])
GUICtrlSendMsg(GUICtrlCreatePic('',0,0,$6[0],$6[1]),370,0,$4)
_IEQuit($1)
GUISetState()
Do
Until GUIGetMsg()=-3
EndFunc

Primeiro, isso não usa o RegEx para raspar o site (porque não tenho tempo para testá-lo em todos os quadrinhos), mas usa a API do Internet Explorer para percorrer as imgtags do DOM até encontrar uma com o texto do título.

O fluxo binário é lido a partir da URL da imagem e renderizado em um bitmap usando GDIPlus. Isso é exibido em uma interface gráfica agradável e de tamanho automático, com uma dica de ferramenta real para que ele se comporte quase exatamente como o site.

Aqui está um caso de teste ( _(859)):

)

mınxomaτ
fonte
4
Seria melhor se você adicionasse o suporte de volta à imagem.
Matt
Uau, acabei de descobrir que eu posso executar o AutoIt no Wine no Ubuntu. Agora, tudo o que preciso fazer é colocar o IE lá.
Pensando bem
2
@ElPedro Se você possui uma CPU moderna, use o qemu KVM e o seamlessRDP (basicamente um paralelo de bricolage para linux) em vez do wine. Isso integra aplicativos do Windows perfeitamente na área de trabalho linux e tem 100% de compatibilidade + passagem de GPU. Apenas uma dica.
mınxomaτ 27/10/16
Obrigado @ mınxomaτ. Eu posso tentar. Eu trabalho com o Windows o dia todo, então prefiro usar o Linux (vários sabores) fora do trabalho, mas estou sempre interessado em experimentar :) Dica recebida com gratidão.
ElPedro 27/10
7

Powershell, 93 bytes

Versão de 93 bytes para usar o visualizador de imagens local.

$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;iwr ("http:"+$n.src) -OutF x.jpg;ii x.*

Economizou 2 bytes removendo aspas duplas desnecessárias e outro lote usando em ("http:"+$n.src)vez de "https://"+$n.src.trim("/")- já que o imgsrc //já vem com ele e o xkcd não requer https.

$n=(iwr xkcd.com/$args).images|?{$_.title};$n.title;saps ("http:"+$n.src)

$n=(iwr "xkcd.com/$args").images|?{$_.title};$n.title;saps ("https://"+$n.src.trim("/"))

extremamente semelhante à resposta do PowerShell de Matts, (provavelmente deve ser um comentário, mas com baixa reputação)

Em vez disso, isso abre uma nova guia / janela no navegador padrão e outras coisas, economizando alguns bytes.

iwr é um apelido para Invoke-WebRequest

sapsé um alias para o Start-Processqual abre 'it' no contexto padrão.

colsw
fonte
Contornando as bordas das regras sobre como abrir uma página da Web existente, porque isso é apenas o lançamento direto do navegador no .jpg preexistente (ou o que seja), mas uma boa resposta.
AdmBorkBork 28/10
@TimmyD pode ter entendido mal aqui, então - eu achei que você pode usar a própria página web xkcd - você pode simplesmente mudar sapspara iwre acrescentar `x.jpg -OutF;. Ii x *` até o fim, se você quer que ele abra no local padrão visualizador de imagens.
colsw
1
O OP especificou que você não tem permissão para abrir uma página da web preexistente. A versão de 93 bytes eu acho que está bem
um spaghetto
Eu não acho que isso sempre funcionará da mesma forma se você der um número que funcione e depois um número que não funcione . Ele abrirá a imagem que existia na execução anterior.
Matt
Aceito a versão de 93 bytes, mas a mais curta viola as condições do quebra-cabeça.
Pavel
4

R, 358 328 310 298 bytes

f=function(x){H="http:";p=paste0;library(XML);a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]];download.file(p(H,a[1]),'a');I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a');d=dim(I)/100;quartz(,d[2],d[1]);par(mar=rep(0,4));frame();rasterImage(I,0,0,1,1);cat(a[2])}

Com novas linhas e comentários:

f=function(x){
H="http:"
p=paste0
library(XML) #Needed for xpathSApply, htmlParse and xmlAttrs
# The following line find the first img element and extract its attributes
a=xpathSApply(htmlParse(p(H,'//xkcd.com/',x)),'//div/img',xmlAttrs)[[1]]
download.file(p(H,a[1]),'a') #Download to a file called 'a'
I=`if`(grepl('png',a[1]),png::readPNG,jpeg::readJPEG)('a') #Check if png or jpeg and load the file accordingly
d=dim(I)/100 #convert dimension from pixel to inches (100 ppi).
quartz(,d[2],d[1]) #open a window of the correct dimension
par(mar=rep(0,4)) #Get rid of margins
frame() #Create empty plot
rasterImage(I,0,0,1,1) #Add png/jpeg to the plot
cat(a[2]) #Print title text to stdout
}

Capturas de tela dos casos de teste:

para x = 1500: para x = 1500 (png)

para x vazio:
para x = ''

caso em que a imagem é um JPEG:
para x = 10 (jpeg)

x = 859:
x = 859

plannapus
fonte
Gostaria de saber se é necessário exibir a imagem nas dimensões corretas. Quando estava brincando com esse desafio, simplesmente o fiz plot.new();rasterImage(...).
Billywob #
@ Billywob Bem, seria completamente distorcido, pois o tamanho padrão para o enredo é 7x7 polegadas. É verdade que o OP não pediu explicitamente que a imagem não fosse distorcida, mas prefiro assim :) No entanto, estou pensando em me livrar do xaxse yaxscomo o resultado ainda será proporcional.
plannapus
3

PHP, 95 bytes

<?php echo str_replace("title=\"","/>",file_get_contents("https://xkcd.com/".$_GET["id"])); ?>

Salve como main.php, execute o servidor

php -S localhost:8123

Abra http: // localhost: 8123 / main.php? Id = 1500

Евгений Новиков
fonte
2

Python 2.7, 309 299 295 274 bytes

Programa completo. Definitivamente mais jogável, mas depois de ler os quadrinhos do xkcd por tanto tempo, não pude deixar isso passar (quem sabe se isso será útil no futuro para navegar facilmente pelo xkcd).

Se nenhuma entrada for passada, obtém o quadrinho atual. Se um número em quadrinhos válido for passado como entrada, ele será obtido. Se uma entrada inválida (não um número em quadrinhos no intervalo válido) for passada, gera um erro.

Quaisquer sugestões sobre como reduzir a contagem de bytes são bem-vindas! Vou revisitar (e adicionar explicação) quando tiver mais tempo.

-10 bytes graças a @Dopapp

-21 bytes graças a @Shebang

import urllib as u,re
from PIL import Image
h='http://';x='xkcd.com/'
o=u.URLopener()
t=u.urlopen(h+x+raw_input()).read()
c=sum([re.findall(r,t)for r in[h+'imgs.'+x+'c.*s/.*\.\w{1,3}','\.\w{1,3}" t.*e="(.*)" a']],[])
Image.open(o.retrieve(c[0],'1.png')[0]).show();print c[1]
Ioannes
fonte
1
Você pode alterar try:...e except:...para try:n=...e except:n='', poupando-lhe 10 bytes no total
Daniel
1
Por que você ainda tem uma trydeclaração? A especificação do programa diz que você sempre obterá um número inteiro positivo.
Kade
@ Shebang também deve retornar os quadrinhos mais recentes quando não houver entrada. Não consegui gerenciar este caso sem abrir a exceção do erro de entrada.
Ioannes #
1
@ Joannes Por que não usar raw_input()? Por padrão, o usuário pode pressionar [Enter]e nconterá a string vazia de qualquer maneira. Se você remover esse bloco try-except e t=u.urlopen(h+x+n).read() -> t=u.urlopen(h+x+raw_input()).read()o reduzirá para 274 bytes.
Kade
Isso não funciona mais, porque os URLs da imagem xkcd são usados https. No entanto, ainda é válido, porque funcionou no momento da postagem. Para que funcione agora, altere a linha 3 para começar com h='https://'+1 byte.
Mego
2

PHP, 42 bytes

<?=@file('http://xkcd.com/'.$_GET[i])[59];

Salve em um arquivo e inicie-o no servidor da sua escolha

Jared Mellentine
fonte
1
Bem-vindo ao PPCG! Eu não sei PHP, mas não parece haver uma parte do seu código que está buscando o texto do título da imagem?
Pavel Pavel
1

JavaScript + HTML, 124 + 18 = 142 bytes

i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))
<img id=B><p id=A>

Solução de origem cruzada, graças à resposta do Kaiido aqui .

//crossorigin.me/Podem ser salvos 17 bytes ( ) se o proxy necessário para se conectar ao xkcd.com puder ser subtraído ( meta post sobre isso ).

Snippet de teste

f=
i=>fetch(`//crossorigin.me/http://xkcd.com/${i||""}/info.0.json`).then(r=>r.json()).then(d=>(A.innerHTML=d.alt,B.src=d.img))
<style>img{width:50%}</style><input id=I> <button onclick="f(I.value)">Run</button><br>
<img id=B><p id=A>

Justin Mariner
fonte
1

Python 3 + Solicitações + PIL, 192 186 bytes

from requests import*
import PIL.Image as f
from io import*
r=get("https://xkcd.com/%s/info.0.json"%input()).json()
f.open(BytesIO(get(r["img"],stream=1).content)).show()
print(r["alt"])

Abre um visualizador de imagens (o que for padrão no sistema em que está sendo executado) contendo os quadrinhos e publica o texto do título no console.

LyricLy
fonte
1

Wolfram Language 45 bytes (Mathematica)

Import["https://xkcd.com/"<>#,"Images"][[2]]&

Uso com número:

%@"1500"

Uso sem número:

%@""
Vitaliy Kaurov
fonte