Desmistificando o desmembramento de Stroustrup do mito “C ++ é somente para programas grandes e complicados”


161

Stroustrup publicou recentemente uma série de posts desmistificando mitos populares sobre C ++ . O quinto mito é: "C ++ é somente para programas grandes e complicados". Para desmascará-lo, ele escreveu um programa C ++ simples, baixando uma página da Web e extraindo links dela . Aqui está:

#include <string>
#include <set>
#include <iostream>
#include <sstream>
#include <regex>
#include <boost/asio.hpp>

using namespace std;

set<string> get_strings(istream& is, regex pat)
{
    set<string> res;
    smatch m;
    for (string s; getline(is, s);)  // read a line
        if (regex_search(s, m, pat))
            res.insert(m[0]);              // save match in set
    return res;
}

void connect_to_file(iostream& s, const string& server, const string& file)
// open a connection to server and open an attach file to s
// skip headers
{
    if (!s)
        throw runtime_error{ "can't connect\n" };

    // Request to read the file from the server:
    s << "GET " << "http://" + server + "/" + file << " HTTP/1.0\r\n";
    s << "Host: " << server << "\r\n";
    s << "Accept: */*\r\n";
    s << "Connection: close\r\n\r\n";

    // Check that the response is OK:
    string http_version;
    unsigned int status_code;
    s >> http_version >> status_code;

    string status_message;
    getline(s, status_message);
    if (!s || http_version.substr(0, 5) != "HTTP/")
        throw runtime_error{ "Invalid response\n" };

    if (status_code != 200)
        throw runtime_error{ "Response returned with status code" };

    // Discard the response headers, which are terminated by a blank line:
    string header;
    while (getline(s, header) && header != "\r")
        ;
}

int main()
{
    try {
        string server = "www.stroustrup.com";
        boost::asio::ip::tcp::iostream s{ server, "http" };  // make a connection
        connect_to_file(s, server, "C++.html");    // check and open file

        regex pat{ R"((http://)?www([./#\+-]\w*)+)" }; // URL
        for (auto x : get_strings(s, pat))    // look for URLs
            cout << x << '\n';
    }
    catch (std::exception& e) {
        std::cout << "Exception: " << e.what() << "\n";
        return 1;
    }
}

Vamos mostrar ao Stroustrup o que é um programa pequeno e legível .

  1. Baixar http://www.stroustrup.com/C++.html
  2. Listar todos os links:

    http://www-h.eng.cam.ac.uk/help/tpl/languages/C++.html
    http://www.accu.org
    http://www.artima.co/cppsource
    http://www.boost.org
    ...
    

Você pode usar qualquer idioma, mas nenhuma biblioteca de terceiros é permitida.

Vencedora

A resposta C ++ ganhou por votos, mas depende de uma biblioteca de terceiros (o que não é permitido por regras) e, junto com outro concorrente próximo Bash , conta com um cliente HTTP invadido (que não funcionará com HTTPS, gzip, redireciona etc.). Então Wolfram é um vencedor claro. Outra solução que se aproxima em termos de tamanho e legibilidade é o PowerShell (com melhorias nos comentários), mas não recebeu muita atenção. Linguagens mainstream ( Python , C # ) também chegaram bem perto.


43
Para cada um dele, fui chamado de pior. Se o objetivo do OP não fosse tentar provar de alguma forma que Stroustrup está errado, concordo com sua avaliação. Mas toda a premissa da pergunta é mostrar como "seu idioma favorito" pode fazer a mesma coisa que essas 50 linhas de C ++ em muito menos linhas de código. O problema é que nenhum dos exemplos faz a mesma coisa. Em particular, nenhuma das respostas realiza nenhuma verificação de erro, nenhuma das respostas fornece funções reutilizáveis, a maioria das respostas não fornece um programa completo. O exemplo Stroustrup fornece tudo isso.
Dunk

19
O que é triste é que sua página da web nem é válida UTF-8 . Agora tenho que resolver isso, apesar da publicidade do servidor dele Content-Type: text/html; charset=UTF-8... vou enviar um e-mail para ele.
Cornstalks

27
@Dunk Os outros exemplos não fornecem funções reutilizáveis ​​porque realizam toda a funcionalidade dessas funções em uma única linha e não faz sentido tornar essa função inteira por si só, e o exemplo C ++ não realiza nenhuma verificação de erro isso não é tratado de forma nativa quase de maneira idêntica, e a frase "programa completo" é quase sem sentido.
Jason

16
"Você pode usar qualquer idioma, mas nenhuma biblioteca de terceiros é permitida." Eu não acho que seja um requisito justo, considerando que boost/asioé usado lá em cima, que é uma biblioteca de terceiros. Quero dizer, como os idiomas que não incluem a busca de url / tcp como parte de sua biblioteca padrão competem?
greatwolf

Respostas:


116

Volfrâmio

Parece trapaça completa

Import["http://www.stroustrup.com/C++.html", "Hyperlinks"]

Então, basta adicionar algumas análises honestas no topo

Cases[
 Import["http://www.stroustrup.com/C++.html", "XMLObject"],
 XMLElement["a", {___, "href" -> link_, ___}, ___] :> 
  link /; StringMatchQ[link, RegularExpression["((http://)?www([./#\\+-]\\w*)+)"]]
, Infinity]

49
Não, eu não vejo nenhuma trapaça aqui. Esse desafio é trazer o melhor do seu idioma. E essa primeira linha é o epítome de "pequeno e legível".
Martin Ender

Uma resposta que pode ignorar os argumentos tolos sobre a captura de links FTP. Brilhante.
Seth Battin

Vim aqui para oferecer esta solução exata, prazer em ver que outras pessoas também a apreciaram.
Michael Stern

@ MartinBüttner Nesse caso, você pode querer considerar downvoting meta.codegolf.stackexchange.com/a/1078/12130
David Mulder

6
@DavidMulder Tecnicamente, a brecha atualmente não é válida, já que a votação é de + 41 / -21 (e a pergunta da brecha afirma que brechas são aceitas se houver pelo menos o dobro de votos positivos e negativos). Uma conversa fechada, é verdade, mas ainda assim. ;) Além disso, este é um concurso de popularidade, não um código de golfe, e, em particular, é um truque para mostrar a facilidade com que isso pode ser feito em um determinado idioma, e é por isso que acho que a brecha não se aplica realmente a de qualquer maneira (esse desafio basicamente exige).
Martin Ender

115

C ++

#include <boost/asio.hpp>
#include <regex>
#include <iostream>
int main() {
    std::string server = "www.stroustrup.com";
    std::string request = "GET http://" + server + "/C++.html HTTP/1.0\r\nHost: " + server + "\r\n\r\n";
    boost::asio::ip::tcp::iostream s{server, "http"};
    s << request;
    std::regex pat{R"((http://)?www([./#\+-]\w*)+)"};
    std::smatch m;
    for (std::string l; getline(s, l);)
        if (std::regex_search(l, m, pat))
            std::cout << m[0] << "\n";
}

A principal falha é a natureza incômoda do boost :: asio, tenho certeza que pode ser ainda mais curta com uma biblioteca melhor.


166
Engraçado como "nenhuma biblioteca de terceiros" significa que o Python ainda pode import urllib2, o C3 ainda pode ser using System.Net, o Haskel pode ainda import Network.HTTP, mas um codificador C ++ deve dar desculpas #include <boost/asio.hpp>como se tivesse um crapton métrico de bibliotecas especializadas em C ++ (e C!) disponíveis para escolher é algo para se envergonhar só porque a comissão não se preocupou em forçar-feed você um específico ...
DevSolar

19
@DevSolar quase fui para a criação de uma segunda conta para lhe dar outra upvote para que o comentário
usuário

15
O @DevSolar System.Netnão é forçado, é apenas uma biblioteca de alta qualidade, seguindo todas as recomendações .NET incluídas no idioma. Existem implementações alternativas, mas ter suporte a HTTP na biblioteca padrão significa escrever aplicativos simples é simples, significa melhor interoperabilidade entre bibliotecas de terceiros, significa menos dependências, significa fácil implementação para fachadas etc. Imagine um mundo sem std::string, imagine como todos usam sua própria biblioteca, imagine todas as dificuldades que acompanham.
Athari

17
@ DevSolar: nãourllib2 é de terceiros. Está no stdlib como no C ++. no Python está sempre disponível, diferentemente do C ++. Se tivéssemos permissão para usar módulos de terceiros; Eu usaria ou em Python. <iostream>urllib2<boost/asio.hpp>lxmlBeautifulSoup
jfs

22
Além disso, acho que o comentário mais importante aqui é que o C ++ não padroniza tanto material em suas bibliotecas padrão quanto outras linguagens, mas ainda existem bibliotecas portáteis robustas amplamente usadas para muitas das mesmas tarefas padrão em linguagens. como python, e algumas dessas bibliotecas são quase um padrão de fato. E parte disso é o resultado do C ++ poder direcionar sistemas embarcados com pequenos binários e bibliotecas pequenas.
Peter Cordes

85

Pure Bash no Linux / OS X (sem utilitários externos)

O software cliente HTTP é notoriamente inchado. Não queremos esse tipo de dependência. Em vez disso, podemos enviar os cabeçalhos apropriados para um fluxo TCP e ler o resultado. Não é necessário chamar utilitários arcaicos como grep ou sed para analisar o resultado.

domain="www.stroustrup.com"
path="C++.html"
exec 3<> /dev/tcp/$domain/80
printf "GET /$path HTTP/1.1\r\nhost: %s\r\nConnection: close\r\n\r\n" "$domain" >&3
while read -u3; do
    if [[ "$REPLY" =~ http://[^\"]* ]]; then
        printf '%s\n' "$BASH_REMATCH"
    fi
done

Meh - Suponho que poderia ser mais legível ...


1
Como este usando identificadores de arquivo unix para os tubos.
Javadba

2
Uau, nunca pensei que alguém pudesse fazer isso sem utilitários externos. Embora pareça a minha festa de 3.2.17 sobre LFS é um pouco obsoleto para que não suporta mapfile:)
Ruslan

@Ruslan Sim, mapfilevem com o bash 4.x. A mesma coisa é totalmente possível com um while readloop também.
Digital Trauma

3
@ Rosslan eu mudei para em while readvez de mapfile. Mais portátil e mais legível, eu acho.
Digital Trauma

1
Também funciona no OS X!
Alex Cohn

65

Python 2

import urllib2 as u, re
s = "http://www.stroustrup.com/C++.html"
w = u.urlopen(s)
h = w.read()
l = re.findall('"((http)s?://.*?)"', h)
print l

Manco, mas funciona


9
Por que não encadear muitas dessas ligações? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Fake Name

13
É curto, mas não é idiomática (contagem de legibilidade em Python)
jfs

24
Hmmm ... se todo o meu código ignorasse erros como este exemplo, 75% a 90% do meu trabalho já seria feito em todos os projetos em que trabalho.
Dunk

20
@ Dunk: Suponha que o exemplo tenha capturado alguma exceção (por exemplo, de urlopen()). O que deve fazer com essa exceção, além de falhar e morrer? Se ele vai falhar e morrer de qualquer maneira, por que não deixar o Python lidar com a falha e a morte e deixar de fora o tratamento de exceção?
Kevin

8
@ Dunk: Se eu estivesse usando o código Python de outra pessoa, prefiro que eles não capturem urlopenerros do que (digamos) pegá-los e ligar sys.exit("something's borked!"). Se eles fizerem o último, eu tenho que pegar SystemExit, o que nunca é divertido.
Kevin

55

C #

using System;
using System.Net;
using System.Text.RegularExpressions;

class Program {
    static void Main() {
        string html = new WebClient().DownloadString("http://www.stroustrup.com/C++.html");
        foreach (Match match in Regex.Matches(html, @"https?://[^""]+"))
            Console.WriteLine(match);
    }
}

4
Você pode usar var htmle provavelmente var matchcortar alguns caracteres.
Superbest

15
@Superbest Eu posso criar nomes com um único caractere e me livrar de htmlvariáveis ​​também, mas não é disso que estou procurando.
Athari

6
@ Superbest não código de golfe . : D
Kroltan 7/15/15

5
Bem, também melhora a legibilidade. Existe alguma razão para não usar varquando isso não afeta a semântica do código?
Superbest

6
@ Superbest: "melhora a legibilidade" é subjetivo. Pessoalmente, acho que declarar explicitamente o tipo da variável melhora a legibilidade (geralmente, como neste código aqui). Eu não quero debater isso, no entanto; Eu só quero salientar que existem visões alternativas.
Cornstalks

54

"Nenhum terceiro" é uma falácia

Eu acho que a suposição de "não de terceiros" é uma falácia. E é uma falácia específica que afeta os desenvolvedores de C ++, pois é muito difícil criar código reutilizável em C ++. Quando você estiver desenvolvendo alguma coisa, mesmo que seja um script pequeno, sempre usará qualquer parte do código reutilizável disponível.

O problema é que, em linguagens como Perl, Python, Ruby (para citar alguns), reutilizar o código de outra pessoa não é apenas fácil, mas é como a maioria das pessoas realmente escreve código na maioria das vezes.

O C ++, com seus requisitos ABI quase impossíveis de manter, torna esse trabalho muito mais difícil; você acaba com um projeto como o Boost, que é um repositório monstruoso de código e com pouca composição fora dele.

Um exemplo de CPAN

Apenas por diversão, aqui está um exemplo baseado em CPAN, com análise adequada do html, em vez de tentar usar o regex para analisar o html

#!/usr/bin/perl
use HTML::LinkExtor;
sub callback {
   my ($tag, %links) = @_;
   print map { "$_\n" } values %links
}
$p = HTML::LinkExtor->new(\&callback, "http://www.stroustrup.com/C++.html");

6
Voto a favor por abordar o ponto das bibliotecas de terceiros, mas: porcaria, tornar código reutilizável em C ++ é tão fácil de queijo quanto em outro idioma. Usando e, especialmente, encontrando reutilizáveis de código pode ser um pouco mais difícil, mas a única coisa que é seriamente problemática é reutilizar compilados artefatos, mas que muitas vezes é um não-problema em linguagens interpretadas como Perl, etc.
Martin Ba

4
Para esticar uma analogia, o Boost é mais parecido com o CPAN - escolha e escolha. Você não chama o CPAN de um "repositório monstruoso de código" só porque há tantas coisas que você não usa?
Martin Ba

22
CPAN é um 'repositório monstruoso de código', por qualquer definição razoável dessas quatro palavras.
GTC

3
@MartinBa Eu discordo, o C ++ é uma linguagem compilada, exigindo que todos os executáveis ​​reconstruam sua pilha completa de dependências porque é difícil manter a compatibilidade com ABI prejudica seriamente a reutilização do código. Para produzir uma biblioteca reutilizável em C ++, é necessário fazer um longo trabalho para garantir que você não se force a sofrer alterações incompatíveis com ABI o tempo todo.
Daniel Ruoso

6
@MartinBa porque ter que reconstruir todo o universo toda vez que você quiser implementar uma tarefa simples é insuportável.
Daniel Ruoso

47

Shell UNIX

lynx -dump http://www.stroustrup.com/C++.html | grep -o '\w*://.*'

Também encontra um ftp://link :)

Outra maneira, sem depender da ://sintaxe:

lynx -dump -listonly http://www.stroustrup.com/C++.html | sed -n 's/^[ 0-9.]\+//p'

38
Não consigo determinar se +1 por que usar um navegador da web para baixar uma página da web é a ferramenta certa para o trabalho ou -1 porque o desafio é escrever um programa para fazer blahblahblah e você acabou de chamar um programa para fazer o blahing.
David Richerby

2
Eu acho que é melhor substituir o lynx por curl ou wget. Eles são mais comumente usados ​​para baixar uma página da web.
Pavel Strakhov

4
@PavelStrakhov eu escolhi lince exatamente porque pode despejar as ligações sem me fazer qualquer coisa :) especial
Ruslan

2
@SteveJessop por "especial", quero dizer, na verdade, analisar ou regexar ou algo assim. Com o lynx, apenas preencho a lista de links (que curl e wget não listam) e removo a numeração. Você pode considerá-lo trapaceiro ou o que seja, mas achei divertido {usar a ferramenta que quase faz perfeitamente o que é necessário}, apenas ajustando a saída.
Ruslan

7
"mas nenhuma biblioteca de terceiros é permitida" . Eu afirmo que lynxé funcionalmente equivalente a uma biblioteca de terceiros nesse cenário.
Digital Trauma

43

CSS 3

* {
  margin: 0;
  padding: 0;
}
*:not(a) {
  font: 0/0 monospace;
  color: transparent;
  background: transparent !important;
}
a {
  content: "";
}
a[href*="://"]::after {
  content: attr(href);
  float: left;
  clear: left;
  display: block;
  font: 12px monospace;
  color: black;
}

Esse código pode ser usado como um estilo de usuário para exibir apenas links absolutos em uma página em uma lista não formatada. Pode não funcionar corretamente se o seu navegador aplicar o tamanho mínimo da fonte.

Funciona corretamente com http://www.stroustrup.com/C++.html(note !importanton background). Para trabalhar em outras páginas com mais estilos, ele deve ser estendido (redefinir mais propriedades, marcar propriedades como importantes etc.).

Versão alternativa que inclui links relativos, exceto os links entre páginas que começam com hashes (infelizmente, depende de um link absoluto codificado):

* {
  margin: 0;
  padding: 0;
}
*:not(a) {
  font: 0/0 monospace;
  color: transparent;
  background: transparent !important;
  float: none !important;
  width: auto !important;
  border: none !important;
}
a {
  content: "";
}
a::after {
  display: none;
}
a:not([href^="#"])::after {
  content: attr(href);
  float: left;
  clear: left;
  display: block;
  font: 12px monospace;
  color: black;
}
a:not([href*="://"])::after {
  content: "http://www.stroustrup.com/" attr(href);
}

16
Esta é a pior coisa que eu já vi. +1
Emmett R.

1
Isso é lindo e completamente horrível. +1
ricdesi

36

Clojure

(->> (slurp "http://www.stroustrup.com")
     (re-seq #"(?:http://)?www(?:[./#\+-]\w*)+"))

28
Slurp ?! Eu preciso aprender Clojure.
11684

10
@ 11684 - Clojure também tem funções padrão nomeados spit, zippere lazy-cat... :-)
Bob Jarvis

2
Uau, acho que será uma resolução de fim de ano novo. @BobJarvis
11684

30

Emacs Lisp

(with-current-buffer (url-retrieve-synchronously "http://www.stroustrup.com/C++.html")
  (while (re-search-forward "https?://[^\\\"]*")
    (print (match-string 0))))

2
Estou um pouco desapontado, dado o quão compacto e eminentemente legível esse código é, por não ter mais votos. Bem feito.
Spacemoose

28

Scala

"""\"(https?://.*?)\"""".r.findAllIn(scala.io.Source.fromURL("http://www.stroustrup.com/C++.html").mkString).foreach(println)

8
embalar tudo em uma linha - C ++ pode fazê-lo também
quetzalcoatl

Que tal ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl - Esta é uma expressão , não apenas uma linha. Você pode excluir todas as quebras de linha do código C ++, mas isso não é a mesma coisa que executar toda a tarefa em uma única expressão.
DaoWen

4
@DaoWen: Desculpe, mas iniciar expressões-contra-linha está ficando bobo. Adicione alguns functors e C ++, você também pode fazê-lo. Mas essa é apenas a questão de quais bibliotecas são consideradas "concedidas" e possuem "código zero". Isso não muda o fato de colocá-lo em uma linha prejudicar a legibilidade. Pode-se mantê-lo imóvel como uma expressão única e apenas reformatá-lo em algumas linhas para ganhar muito e perder nada além de ... contagem de linhas. Esse é meu argumento. Embalagem boba - C ++ também pode fazê-lo. Se alguém quiser sair da caixa "embalagem boba", formate o código para facilitar a leitura, não a contagem de linha.
Quetzalcoatl

3
@quetzalcoatl Tobias não colocou o link lá para seguirmos. Ele estava perguntando ao escritor dessa resposta por que não estava em seus resultados.
perfil completo de JLRishe

25

PHP 5

<?php
preg_match_all('/"(https?:\/\/.*?)"/',file_get_contents('http://www.stroustrup.com/C++.html'),$m);
print_r($m[1]);

5
Edições sugeridas: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(atualmente um erro); remove array_unshift($m);(atualmente um erro, você provavelmente quis dizer array_shift); print_r($m);print_r($m[1]);(apenas produz os URLs).
Primo

fixos, obrigado pela sua entrada
David Xu

@DavidXu Exceto que você não consertou ...?
Shahar

agora está consertado.!
David Xu

25

PowerShell

Pesquisa de texto para todos os URLs totalmente qualificados (incluindo JavaScript, CSS etc.):

[string[]][regex]::Matches((iwr "http://www.stroustrup.com/C++.html"), '\w+://[^"]+')

Ou para obter links apenas em tags âncora (inclui URLs relativos):

(iwr "http://www.stroustrup.com/C++.html").Links | %{ $_.href }

Versões mais curtas dos comentários:

(iwr "http://www.stroustrup.com/C++.html").Links.href
(iwr "http://www.stroustrup.com/C++.html").Links.href-match":"

6
Se alguém se perguntar, iwré um apelido para Invoke-WebRequest(PS3 +).
Athari

8
Você poderia abusar ânsia do PowerShell para achatar coleções e fazer: (iwr "http://www.stroustrup.com/C++.html").Links.href(ou (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"apenas absoluta da URI)
Mathias R. Jessen

1
Isso é bastante útil!
precisa saber é o seguinte

22

D

import std.net.curl, std.stdio;
import std.algorithm, std.regex;

void main() {
foreach(_;byLine("http://www.stroustrup.com/C++.html")
    .map!((a)=>a.matchAll(regex(`<a.*?href="(.*)"`)))
    .filter!("a")){ writeln(_.front[1]); }
}

Para fazer a lista semelhante ao exemplo original, você poderia tubo de saída do programa através de | sort | uniqou em vez adicionar import std.arraye alterar a linha .filter!("a")){ writeln(_.front[1]); }para o seguinte: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Observe, no entanto, que eu apenas tentei esse código e não provei que ele estivesse correto ou "idiomático". :)
Frg

22

Node.js

var http = require('http');

http.get('http://www.stroustrup.com/C++.html', function (res) {
    var data = '';
    res.on('data', function (d) {
        data += d;
    }).on('end', function () {
        console.log(data.match(/"https?:\/\/.*?"/g));
    }).setEncoding('utf8');
});

3
Eu me pergunto se require('http').getfunciona. Se isso acontecer, podemos abandonar a instrução var e encurtar outra linha.
Unihedron

@Unihedro Sim.
TimWolla

9
@Unihedro Sim, mas este não é um concurso de golfe.
CPu1

Você não precisa usar nenhum grupo de captura.
Ry-

Eu acho que é JavaScript, e não um nome de estrutura.
Mr5

20

Rubi

require 'net/http'
result = Net::HTTP.get(URI.parse('http://www.stroustrup.com/C++.html'))
result.scan(/"((http)s?://.*?)"/)

1
Seu regex falhará, você precisa usar %r{"(https?://[^"]+)"}. Além disso, você pode usar Net::HTTP.get('www.stroustrup.com', '/C++.html')para encurtar a solicitação (e mantê-la legível). Assim código inteira pode estar em uma linha (mantendo-legível): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Execute-o ruby -rnet/httpe você nem precisa de require 'net/http'linha.
Hauleth

20

Haskell

Alguns problemas "\w"no Text.Regex.Posix

import Network.HTTP
import Text.Regex.Posix
pattern = "((http://)?www([./#\\+-][a-zA-Z]*)+)"
site = "http://www.stroustrup.com/C++.html"

main = do
    file <- getResponseBody =<< simpleHTTP (getRequest site)
    let result = getAllTextMatches $ file =~ pattern
    putStr $ unlines result -- looks nicer

Por que o tipo de resultespecificado é explicitamente? Deve ser totalmente restringido pelo seu uso em unlines.
John Dvorak

1
Isso amplia um pouco as regras, visto que Network.HTTPnem TextRegex.Posixexistem nem estão no basepacote. (Embora estejam na plataforma Haskell e, é claro, no Hackage, então ...)
deixaram de girar no sentido contrário ao horário de

1
@ JanDvorak, começo a escrever em ghci (provavelmente devo publicá-lo inalterado). Mas sua nota é relevante, obrigado.
vlastachu

@leftaroundabout, não sabia. Parece que eu não poderia ter feito, se tivesse usado o pacote base.
precisa saber é

networktambém não baseestá presente, portanto, exceto para rolar suas próprias ligações de soquete, não há maneira prática de fazer isso apenas base.
Lambda Fairy

18

PHP

Tanto quanto posso dizer, a maioria das instalações PHP modernas vem com processamento DOM, então aqui está uma que realmente atravessa as âncoras dentro do HTML:

foreach (@DOMDocument::loadHTMLFile('http://stroustrup.com/C++.html')->getElementsByTagName('a') as $a) {
    if (in_array(parse_url($url = $a->getAttribute('href'), PHP_URL_SCHEME), ['http', 'https'], true)) {
        echo $url, PHP_EOL;
    }
}

O loop interno pode ser reduzido para:

preg_match('~^https?://~', $url = $a->getAttribute('href')) && printf("%s\n", $url);

Na verdade, queria chegar a isso (como minha primeira resposta aqui). Você fez isso primeiro, então aqui está o seu +1 (por não usar um Regex propenso a erros)! Dica: você pode usar um coxo em 1vez de truepara a in_arraypesquisa estrita. Você também pode omitir os colchetes. Não tenho certeza absoluta, mas você pode também largar o httpe sair do ://(sem o esquema). .
kaiser

E: Outra possibilidade seria deixar cair o if ( ) {}favor de in_array() and print $url.PHP_EOL. Mas sim, você teria outra +1 (se pudesse) para melhor legibilidade :)
kaiser

Apenas tentei o seu exemplo e recebi um erro para padrões rígidos (PHP 5.4). Parece que na fonte, há um link corrompido ou formatado incorretamente com um ponto e vírgula ausente. Você pode desativar o relatório de erros usando @\DOMDocument. Só tentei isso e posso confirmar que funciona.
kaiser

Não, é a documentação que está errada; tecnicamente, você não deve ligar ::loadHTMLFile()estaticamente e adicionar @apenas oculta esse artefato.
Jack

2
Essa é definitivamente uma das soluções mais "corretas", uma das únicas que eu pude ver em uso na produção. bom trabalho
Jordon Biondo

14

Shell Unix

wget -q -O - http://www.stroustrup.com/C++.html | sed -n '/http:/s/.*href="\([^"]*\)".*/\1/p' | sort

Embora eu tenha que admitir que isso não funciona se houver mais de um link em uma linha.


1
curl http://www.stroustrup.com/C++.htmlsalva alguns caracteres.
L0b0

7
"mas nenhuma biblioteca de terceiros é permitida" . Eu acho que desde que wgeté GNU (como é o bash), você poderia argumentar que não é de terceiros. Mas curldefinitivamente é de terceiros.
Digital Trauma

Que tal ftp://ftp.research.att.com/pub/c++std/WP/CD2e https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

4
@TobiasKienzler Acho código original do Stroustrup não encontrá-los tanto
Ruslan

14

Java

import java.util.regex.*;
class M{
    public static void main(String[]v)throws Throwable{
        Matcher m = Pattern.compile( "\"((http)s?://.*?)\"" )
            .matcher(
                 new Scanner(
                         new URL( "http://www.stroustrup.com/C++.html" )
                             .openStream(),
                         "UTF-8")
                     .useDelimiter("\\A")
                     .next());
        while(m.find())
            System.out.println(m.group());
    }
}

3
Você poderia formatar o código corretamente em suas respostas? Não é uma competição pelo código menos legível. Você pode formatá-lo para evitar barras de rolagem horizontais, pelo menos.
Athari

Se você usar um, Scannerpoderá fazê-lo processar o padrão de expressão regular para links diretamente e iterar sobre os Scannerresultados.
Holger

5
Sim .. isso é java para você. Usá-lo para o código de golfe é uma tarefa corajosa.
Javadba

4
Nunca pensei que veria uma solução java realmente menor que C ++!
Slebetman

2
Correção no meu último comentário: devo admitir que esse é o código mais curto e mais limpo que pode ser escrito em Java. Tentei uma abordagem do analisador SAX, que pode ser ainda mais curta com as lambdas, mas a página da web não é XHTML e o analisador lança exceções. Regex é o único caminho a percorrer.
Mister Smith

11

Groovy

"http://www.stroustrup.com/C++.html".toURL().text.findAll(/https?:\/\/[^"]+/).each{println it}

Pode ser melhorado usando? operador para evitar NPEs?
Chris K

2
@ChrisKaminski e seja o primeiro (ao lado de Bjarne) por aqui a verificar erros? Nunca! além disso: só vejo exceções relacionadas a E / S aqui. onde você vê um NPE?
Cfrick

findAll () poderia retornar nulo, não? Ou ele retornará uma lista vazia? Ainda um pouco novo para o Groovy. EDIT: nm, parece que findAll () retorna uma lista vazia. Aqueles caras Groovy eram tão inteligentes. :-)
Chris K

11

SQL (SQL Anywhere 16)

Definir um procedimento armazenado para buscar a página da web

CREATE OR REPLACE PROCEDURE CPPWebPage()
URL 'http://www.stroustrup.com/C++.html'
TYPE 'HTTP';

Produza o conjunto de resultados usando uma única consulta

SELECT REGEXP_SUBSTR(Value,'"https?://[^""]+"',1,row_num) AS Link  
FROM (SELECT Value FROM CPPWebPage() WITH (Attribute LONG VARCHAR, Value LONG VARCHAR) 
      WHERE Attribute = 'Body') WebPage, 
      sa_rowgenerator( 1, 256 ) 
WHERE Link IS NOT NULL;

Limitações: Isso produz até 256 links. Se existirem mais links, aumente os 256 para um valor apropriado.


2
Eu não acreditava que haveria golfe no SQL ... até agora.
precisa saber é

Entendi ... "links". :-)
Jack na SAP Canada

10

CoffeeScript / NodeJS

require('http').get 'http://www.stroustrup.com/C++.html', (r) ->
    dt = '';
    r.on 'data', (d) -> dt += d
    r.on 'end' , (d) -> console.log dt.match /"((http)s?:\/\/.*?)"/g

1
Eu acho que isso é CoffeeScript / Node? Eu acho que você deve especificar que ...
John Dvorak

Uau. Isso é muito legível.
slebetman

@slebetman ele definitivamente é pequena embora
John Dvorak

@slebetman Sim CoffeeScript é muito mais legível do que JavaScript :) Eu estava feliz por se livrar de todas as chaves} :)
Robau

9

Perl

use LWP;
use feature 'say';

my $agent = new LWP::UserAgent();
my $response = $agent->get('http://www.stroustrup.com/C++.html');

say for $response->content =~ m<"(https?://.+?)">g;

1
O código ficaria mais claro se você evitasse as variáveis ​​separador de campo e separador de registro e apenas o fizesse: print map {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso

@DanielRuoso concordou.
Primo

ou mesmo use v5.10;e say for $response->content...
Mark Reed

Para cada um, suponho. Alguns dos recursos perl6 com backport foram problemáticos (correspondência inteligente, estou olhando para você), mas saysão bastante úteis e, em minha opinião, mais claros aqui. (Além disso, houve sim uma série de melhorias completamente-não relacionados-se perl6ism para perl5 nos últimos 13 anos, que poderia ser a pena conferir.)
Mark Reed

@ MarkReed Concordo que sayprovavelmente seja mais legível nesse caso, principalmente para aqueles menos familiarizados com o perl.
Primo

9

R

html<-paste(readLines("http://www.stroustrup.com/C++.html"),collapse="\n")
regmatches(html,gregexpr("http[^([:blank:]|\\\"|<|&|#\n\r)]+",html))

... embora R seja escrito principalmente em C ... provavelmente algumas linhas de código C por trás dessas 2 linhas de código R.


2
Isso (ou algo semelhante) é verdade para praticamente todas as respostas aqui.
perfil completo de JLRishe

8

Objetivo-C

NSString *s;
for (id m in [[NSRegularExpression regularExpressionWithPattern:@"\"((http)s?://.*?)\"" options:0 error:nil] matchesInString:(s=[NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.stroustrup.com/C++.html"]])]){
    NSLog(@"%@",[s substringWithRange:[m range]]);
}

3
O que? Por favor, escreva a versão Swift. Esse absurdo colchete está prejudicando os olhos :)
Sr. Smith

2
Viva para []! Além disso, devemos acrescentar totalmente uma versão Smalltalk;)
Bersaelor

A resposta @MisterSmith Swift agora está disponível aqui .
JAL

7

Tcl

package require http
set html [http::data [http::geturl http://www.stroustrup.com/C++.html]]
puts [join [regexp -inline -all {(?:http://)?www(?:[./#\+-]\w*)+} $html] \n]

Você pode se safar fazendo http :: data dentro do put. Não há necessidade de criar uma variável temporária. E eu também o formataria colocando novas linhas e recuando a cada momento [. Mas essa é uma escolha de estilo.
Slebetman

7

Ir

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "os"
    "regexp"
)

func main() {
    resp, err := http.Get("http://www.stroustrup.com/C++.html")
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    defer resp.Body.Close()
    data, _ := ioutil.ReadAll(resp.Body)
    results := regexp.MustCompile(`https?://[^""]+`).FindAll(data, -1)
    for _, row := range results {
        fmt.Println(string(row))
    }
}

PS esse código lê toda a fonte na memória, então considere usar regexp.FindReaderIndexpara pesquisar no fluxo, para tornar o aplicativo à prova de balas.


6

CJam

O CJam não possui regex, então tive que usar uma abordagem diferente nesta:

"http://www.stroustrup.com/C++.html"g''/'"*'"/(;2%{_"http://"#!\"https://"#!e|},N*

Primeiro converto tudo 'para ", depois divido sobre tudo ", pego todas as strings alternativas e, finalmente, filtre essa lista por strings começando com http://or https://. Depois disso, basta imprimir cada sequência filtrada em uma nova linha.

Experimente usando o interpretador Java como

java -jar cjam-0.6.2.jar file.cjam

onde file.cjam possui o conteúdo do código acima.


9
Não sei sobre a parte legível ... não sabia Cjam tem a funcionalidade web
Def

Se você quer jogar golfe ... ''/'"f/:+por ''/'"*'"/'"f/0f=.
precisa saber é o seguinte

... espere por que '"f/0f=existe? Isso deveria fazer alguma coisa ( 2%por exemplo)?
precisa saber é o seguinte

6

F #

Esse código pode ser muito mais curto, mas eu escreveria algo assim se esperasse ter que ler ou usar esse código novamente, para que ele tenha muitas anotações de tipo desnecessárias. Demonstra o uso de um padrão ativo MatchValue para habilitar a correspondência de padrões com o tipo CLR padrão Match

open System.Net

let (|MatchValue|) (reMatch: Match) : string = reMatch.Value

let getHtml (uri : string) : string = 
    use webClient = WebClient() in
        let html : string = webClient.DownloadString(uri)
        html

let getLinks (uri : string) : string list =
    let html : string = getHtml uri
    let matches : MatchCollection = Regex.Matches(html, @"https?://[^""]+") 
    let links = [ for MatchValue reMatch in matches do yield reMatch ]
    links

let links = getLinks "http://www.stroustrup.com/C++.html" 
for link in links do
    Console.WriteLine(link)

Editar Eu criei a função getLinks


Eu realmente gosto de como você usou anotações de tipo. Acho que nomear valores para descrever o que você retorna está ok, mas o nome da função é expressivo o suficiente: valor getHTML e html, valor getLinks e links. As duas últimas linhas podem ser links |> Seq.iter (printfn "% s")
MichalMa

@MichalMa Concordo que o nome da função é expressivo o suficiente por si só, as variáveis ​​html e links estão lá por razões pragmáticas: portanto, há um lugar para definir um ponto de interrupção. Eu usei o loop for em vez do List.iter apenas porque gosto da maneira como ele lê mais, embora em um repl eu provavelmente usasse o List.iter.
precisa saber é o seguinte
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.