Debunking Il debunking del mito di Stroustrup "Il C ++ è solo per programmi grandi e complessi"


161

Stroustrup ha recentemente pubblicato una serie di post che sfatano i miti popolari sul C ++ . Il quinto mito è: "C ++ è solo per programmi grandi, complicati". Per sfatarlo, scrisse un semplice programma C ++ scaricando una pagina Web ed estraendo collegamenti da essa . Ecco qui:

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

Mostriamo a Stroustrup che cos'è in realtà un programma piccolo e leggibile .

  1. Scaricare http://www.stroustrup.com/C++.html
  2. Elenca tutti i collegamenti:

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

È possibile utilizzare qualsiasi lingua, ma non sono consentite librerie di terze parti.

Vincitore

Risposta C ++ vinta dai voti, ma si basa su una libreria di terze parti (che non è consentita dalle regole) e, insieme a un altro concorrente stretto Bash , si affida a un client HTTP hackerato insieme (non funzionerà con HTTPS, gzip, reindirizzamenti ecc.). Quindi Wolfram è un chiaro vincitore. Un'altra soluzione che si avvicina in termini di dimensioni e leggibilità è PowerShell (con miglioramento dai commenti), ma non ha ricevuto molta attenzione. Anche le lingue mainstream ( Python , C # ) si sono avvicinate abbastanza.


43
A ciascuno il suo, sono stato chiamato peggio. Se l'obiettivo del PO non fosse quello di provare e in qualche modo dimostrare che Stroustrup è sbagliato, sarei d'accordo con la tua valutazione. Ma l'intera premessa della domanda è mostrare come "la tua lingua preferita" possa fare la stessa cosa di queste 50 righe di C ++ in molte meno righe di codice. Il problema è che nessuno degli esempi fa la stessa cosa. In particolare, nessuna delle risposte esegue alcun controllo degli errori, nessuna delle risposte fornisce funzioni riutilizzabili, la maggior parte delle risposte non fornisce un programma completo. L'esempio di Stroustrup fornisce tutto ciò.
Dunk

19
La cosa triste è che la sua pagina web non è nemmeno valida UTF-8 . Ora devo risolvere il problema, nonostante la sua pubblicità sul server Content-Type: text/html; charset=UTF-8... Gli invierò un'e-mail.
Cornstalks,

27
@Dunk Gli altri esempi non forniscono funzioni riutilizzabili perché eseguono l'intera funzionalità di quelle funzioni in una sola riga e non ha senso rendere l'intera funzione autonoma, e l'esempio C ++ non esegue alcun controllo degli errori che non è gestito in modo nativo in modo quasi identico e la frase "programma completo" è quasi insignificante.
Jason,

16
"È possibile utilizzare qualsiasi lingua, ma non sono consentite librerie di terze parti." Non penso che sia un requisito equo considerando che boost/asioviene utilizzata lassù che è una libreria di terze parti. Voglio dire come competeranno le lingue che non includono il recupero url / tcp come parte della sua libreria standard?
greatwolf il

Risposte:


116

Wolfram

Sembra un imbroglio completo

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

Quindi aggiungi solo un po 'di analisi onesta in cima

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

49
No, non vedo alcun imbroglione qui. Questa sfida consiste nel far emergere il meglio della tua lingua. E quella prima riga è l'epitome di "piccolo e leggibile".
Martin Ender,

Una risposta che può ignorare gli argomenti sciocchi sulla cattura di collegamenti ftp. Brillante.
Seth Battin,

Sono venuto qui per offrire questa soluzione esatta, felice di vedere che anche altri l'hanno apprezzata.
Michael Stern,

@ MartinBüttner In tal caso potresti prendere in considerazione la possibilità di effettuare il
David Mulder,

6
@DavidMulder Tecnicamente, la scappatoia non è attualmente valida, poiché la ripartizione del voto è + 41 / -21 (e la domanda sulla scappatoia afferma che le scappatoie sono accettate se ci sono almeno il doppio di voti rispetto a quelli negativi). Una chiamata ravvicinata, certo, ma comunque. ;) Inoltre, questa è una gara di popolarità, non un codice golf, e in particolare, è un pop-con per mostrare quanto facilmente si può fare in una determinata lingua, motivo per cui penso che la scappatoia non si applichi realmente a questa sfida comunque (dal momento che la sfida sostanzialmente lo richiede).
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";
}

Il principale difetto è la natura scomoda di boost :: asio, sono sicuro che può essere ancora più breve con una libreria migliore.


166
Divertente come "nessuna libreria di terze parti" significa che Python può ancora import urllib2, C3 può ancora essere using System.Net, Haskel può ancora import Network.HTTP, ma un programmatore C ++ deve fare delle scuse per #include <boost/asio.hpp>avere una metrica crapton di librerie C ++ (e C!) Appositamente costruite disponibile tra cui scegliere è qualcosa di cui vergognarsi solo perché il comitato non si è preoccupato di alimentarti forzatamente con uno specifico ...
DevSolar

19
@DevSolar è quasi andato per la creazione di un secondo account per darti un altro voto per quel commento
utente

15
@DevSolar System.Netnon è forzato, è solo una libreria di alta qualità che segue tutti i consigli .NET inclusi nella lingua. Esistono implementazioni alternative, ma avere il supporto HTTP nella libreria standard significa scrivere semplici app è semplice, significa una migliore interoperabilità tra librerie di terze parti, significa meno dipendenze, significa facile implementazione per facciate ecc. Immagina un mondo senza std::string, immagina come tutti usano la propria biblioteca, immagina tutte le difficoltà che ne derivano.
Athari,

17
@DevSolar: nonurllib2 è di terze parti. È in stdlib come in C ++. in Python è sempre disponibile a differenza di C ++. Se ci fosse permesso di usare moduli di terze parti; Vorrei usare o in Python. <iostream>urllib2<boost/asio.hpp>lxmlBeautifulSoup
jfs,

22
Inoltre, penso che il commento più importante qui sia solo che C ++ non standardizza tanto roba nelle sue librerie standard come altre lingue, ma ci sono ancora librerie portatili robuste ampiamente usate per molte delle stesse attività che sono standard nelle lingue come Python e alcune di queste librerie sono quasi uno standard di fatto. E parte di questo è il risultato del fatto che C ++ è in grado di indirizzare i sistemi embedded con piccoli binari e piccole librerie.
Peter Cordes,

85

Pure Bash su Linux / OS X (nessuna utility esterna)

Il software client HTTP è notoriamente gonfio. Non vogliamo questo tipo di dipendenze. Possiamo invece spingere le intestazioni appropriate in un flusso TCP e leggere il risultato. Non è necessario chiamare utilità arcaiche come grep o sed per analizzare il risultato.

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 - Suppongo che potrebbe essere più leggibile ...


1
Come questo usando gli handle di file unix per le pipe.
Javavba,

2
Wow, non avrei mai pensato di poterlo fare senza utility esterne. Anche se sembra che il mio bash 3.2.17 su LFS sia un po 'obsoleto, quindi non supporta mapfile:)
Ruslan

@Ruslan Yep, mapfileviene fornito con bash 4.x. La stessa cosa è totalmente fattibile anche con un while readloop.
Trauma digitale

3
@Ruslan L'ho cambiato in while readinvece di mapfile. Più portatile e più leggibile, credo.
Trauma digitale

1
Funziona anche su 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

Lame, ma funziona


9
Perché non concatenare molte di queste chiamate? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Nome falso

13
È breve ma non è idiomatico (la leggibilità conta in Python)
jfs

24
Hmmm ... se tutto il mio codice ignorasse errori come questo esempio, dal 75% al ​​90% del mio lavoro sarebbe già fatto su ogni progetto su cui lavoro.
Dunk

20
@Dunk: supponiamo che nell'esempio sia stata rilevata qualche eccezione (ad es. Da urlopen()). Cosa dovrebbe fare con un'eccezione del genere, a parte crash e die? Se sta per andare in crash e morire comunque, perché non lasciare che Python gestisca il crash-and-die e lasci del tutto la gestione delle eccezioni?
Kevin,

8
@Dunk: se stavo usando il codice Python di qualcun altro, preferirei che non rilevassero urlopenerrori piuttosto che (diciamo) catturarli e chiamarli sys.exit("something's borked!"). Se lo fanno, devo catturare SystemExit, il che non è mai divertente.
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
Puoi usare var html, e probabilmente var matchper radere via alcuni personaggi.
Superbo

15
@Superbest Riesco a creare nomi a carattere singolo e anche a liberarmi del htmltutto dalla variabile, ma non è quello che sto cercando .
Athari,

6
@Superbest non code-golf . : D
Kroltan,

5
Bene, migliora anche la leggibilità. C'è mai un motivo per non usarlo varquando non avrà impatto sulla semantica del codice?
Superbo

6
@Superbest: "migliora la leggibilità" è soggettivo. Personalmente, penso che affermare esplicitamente il tipo di variabile migliora la leggibilità (di solito, come in questo codice qui). Non voglio discuterne, però; Voglio solo sottolineare che esistono punti di vista alternativi.
Cornstalks,

54

"No di terze parti" è un errore

Penso che il presupposto "no di terze parti" sia un errore. Ed è un errore specifico che affligge gli sviluppatori C ++, poiché è così difficile rendere il codice riutilizzabile in C ++. Quando stai sviluppando qualcosa, anche se si tratta di un piccolo script, farai sempre uso di tutti i pezzi di codice riutilizzabili disponibili.

Il fatto è che in lingue come Perl, Python, Ruby (solo per citarne alcuni), riutilizzare il codice di qualcun altro non è solo facile, ma è come la maggior parte delle persone scrive il codice la maggior parte delle volte.

Il C ++, con i suoi requisiti ABI compatibili quasi impossibili da mantenere, rende un lavoro molto più difficile, si finisce con un progetto come Boost, che è un mostruoso repository di codice e pochissima componibilità al di fuori di esso.

Un esempio di CPAN

Solo per divertimento, ecco un esempio basato su CPAN, con una corretta analisi dell'html, invece di provare a usare regex per analizzare l'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
È utile per affrontare il problema delle librerie di terze parti, ma: merda, rendere il codice riutilizzabile in C ++ è facile e sdolcinato come in altre lingue. L'uso e soprattutto la ricerca di codice riutilizzabile può essere un po 'più difficile, ma l'unica cosa che è seriamente problematica è il riutilizzo di artefatti compilati , ma questo è spesso un problema in linguaggi interpretati come Perl, ecc.
Martin Ba

4
Per ampliare un'analogia, Boost è più simile a CPAN: scegli e scegli. Non chiami CPAN un "repository mostruoso di codice" solo perché ci sono così tante cose che non usi?
Martin Ba

22
CPAN è un "repository mostruoso di codice", secondo una definizione ragionevole di queste quattro parole.
jwg

3
@MartinBa Non sono d'accordo, essendo C ++ un linguaggio compilato, che richiede a tutti i file eseguibili di ricostruire l'intero stack di dipendenze perché è difficile mantenere la compatibilità ABI che ostacola seriamente la riusabilità del codice. Al fine di produrre una libreria riutilizzabile in C ++, è necessario passare attraverso lunghezze davvero lunghe al fine di assicurarsi di non imporre continuamente modifiche incompatibili ABI.
Daniel Ruoso,

6
@MartinBa perché dover ricostruire l'intero universo ogni volta che vuoi implementare un semplice compito è insopportabile.
Daniel Ruoso,

47

Shell UNIX

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

Trova anche un ftp://link :)

Un altro modo, senza fare affidamento sulla ://sintassi:

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

38
Non riesco a capire se fare +1 perché usare un browser Web per scaricare una pagina Web è lo strumento giusto per il lavoro o -1 perché la sfida è scrivere un programma per fare blahblahblah e hai appena chiamato un programma da fare il blahing.
David Richerby,

2
Penso che sia meglio sostituire la lince con arricciatura o wget. Sono più comunemente usati per scaricare una pagina web.
Pavel Strakhov,

4
@PavelStrakhov Ho scelto lynx esattamente perché può scaricare i collegamenti senza che io faccia nulla di speciale :)
Ruslan,

2
@SteveJessop per "speciale" intendo effettivamente analizzare o regex o altro. Con lynx ho appena estratto l'elenco dei collegamenti (che arricciano e wget non elencano) e rimuovo la numerazione. Potresti considerarlo un imbroglio o altro, ma ho pensato che fosse divertente {usare lo strumento che fa quasi perfettamente ciò che è richiesto}, semplicemente perfezionando l'output.
Ruslan,

7
"ma non sono consentite librerie di terze parti" . Sostengo che lynxsia funzionalmente equivalente a una libreria di terze parti in questo scenario.
Trauma digitale

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

Questo codice può essere utilizzato come stile utente per visualizzare solo collegamenti assoluti su una pagina in un elenco non formattato. Potrebbe non funzionare correttamente se il tuo browser applica dimensioni minime del carattere.

Funziona correttamente con http://www.stroustrup.com/C++.html(nota !importantsu background). Per funzionare su altre pagine con più stili, è necessario estenderlo (ripristinare più proprietà, contrassegnare le proprietà come importanti ecc.).

Versione alternativa che include collegamenti relativi tranne i collegamenti intrapage che iniziano con gli hash (purtroppo si basa su un collegamento assoluto codificato):

* {
  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
Questa è la cosa peggiore che abbia mai visto. +1
Emmett R.

1
Questo è bellissimo e completamente orribile. +1
ricdesi

36

Clojure

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

28
Slurp ?! Devo imparare Clojure.
11684

10
@ 11684 - Clojure ha anche funzioni standard di nome spit, zippere lazy-cat... :-)
Bob Jarvis

2
Wow, penso che sarà una risoluzione per Capodanno in ritardo. @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
Sono un po 'deluso, visto quanto è compatto ed eminentemente leggibile questo codice, che non ha più voti. Molto bene.
Spaziale

28

Scala

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

8
impacchettare tutto in una riga - C ++ può farlo anche
quetzalcoatl

Che dire ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler,

22
@quetzalcoatl - Questa è un'espressione , non solo una riga. Puoi semplicemente eliminare tutte le interruzioni di riga dal codice C ++, ma non è la stessa cosa che fare l'intera attività in una singola espressione.
DaoWen,

4
@DaoWen: Siamo spiacenti, ma iniziare espressioni-vs-linea sta diventando sciocco. Aggiungi alcuni funzioni e C ++ puoi farlo anche tu. Ma questa è solo la domanda su quali librerie siano considerate "concesse" e con "codice zero all'interno". Non cambia il fatto che impacchettandolo in una leggibilità della linea hurst. Si può tenerlo fermo come una singola espressione e riformattarlo in poche righe per guadagnare molto e perdere nient'altro che il conteggio delle righe. Questo è il mio punto. Imballaggio sciocco: anche C ++ può farlo. Se qualcuno vuole uscire dalla casella "Imballaggio stupido", dovrebbe formattare il codice per leggibilità, non Linecount.
quetzalcoatl,

3
@quetzalcoatl Tobias non ha inserito il link per consentirci di seguirlo. Stava chiedendo allo scrittore questa risposta perché non era nei suoi risultati.
JLRishe

25

PHP 5

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

5
Modifiche suggerite: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(attualmente un errore); rimuovi array_unshift($m);(attualmente un errore, probabilmente intendevi array_shiftinvece); print_r($m);print_r($m[1]);( emette solo gli URL).
primo

risolto, grazie per il tuo contributo
David Xu

@DavidXu Tranne il fatto che non l'hai risolto ...?
Shahar,

ora è risolto.!
David Xu,

25

PowerShell

Ricerca di testo per tutti gli URL completi (inclusi JavaScript, CSS, ecc.):

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

Oppure per ottenere collegamenti solo nei tag di ancoraggio (include URL relativi):

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

Versioni più brevi dai commenti:

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

6
Se qualcuno si chiede, iwrè un alias per Invoke-WebRequest(PS3 +).
Athari,

8
Potresti abusare dell'entusiasmo di PowerShell per appiattire le raccolte e fare: (iwr "http://www.stroustrup.com/C++.html").Links.href(o (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"solo per URI assoluti)
Mathias R. Jessen

1
È abbastanza utile!
Justin Dunlap,

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

Per rendere l'elenco simile all'esempio originale, è possibile tubo di uscita del programma attraverso | sort | uniqo invece aggiungere import std.arraye modificare la riga .filter!("a")){ writeln(_.front[1]); }in questo modo: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Si noti, tuttavia, che ho solo provato questo codice e non ho dimostrato che sia corretto o "idiomatico". :)
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
Mi chiedo se require('http').getfunzioni. In tal caso, possiamo abbandonare l'istruzione var e accorciare un'altra riga.
Unihedron,

@Unihedro Lo fa.
TimWolla,

9
@Unihedro Sì, ma questa non è una gara di golf.
cPu1

Non è necessario utilizzare alcun gruppo di acquisizione.
Ry,

Penso che sia JavaScript piuttosto che un nome di framework.
sig. 5

20

Rubino

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

1
Il tuo regex fallirà, devi usarlo %r{"(https?://[^"]+)"}. Inoltre è possibile utilizzare Net::HTTP.get('www.stroustrup.com', '/C++.html')per abbreviare la richiesta (e mantenerla leggibile). Quindi tutto il codice può essere in una linea (mantenendolo leggibile): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Eseguilo con ruby -rnet/httpe non hai nemmeno bisogno di require 'net/http'linea.
Hauleth,

20

Haskell

Alcuni problemi con "\w"in 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

Perché il tipo di viene resultspecificato esplicitamente? Dovrebbe essere completamente vincolato dal suo uso in unlines.
John Dvorak,

1
Ciò allungare le regole un po ', visto che non Network.HTTPne TextRegex.Posixsono nel basepacchetto. (Anche se sono nella piattaforma Haskell, e ovviamente su Hackage, quindi ...)
cessò di girare in senso antiorario il

1
@ JanDvorak, comincio a scrivere in ghci (probabilmente dovrei postarlo invariato). Ma la tua nota è pertinente, grazie.
vlastachu,

@leftaroundabout, non lo sapevo. Sembra che non avrei potuto farlo, se avessi usato il pacchetto base.
vlastachu,

networknon è nemmeno in base, quindi, salvo per il rotolamento dei propri attacchi socket, non c'è modo pratico per farlo con il solo base.
Lambda Fairy,

18

PHP

Per quanto ne so, la maggior parte delle moderne installazioni PHP sono dotate di elaborazione DOM, quindi eccone una che attraversa effettivamente le ancore all'interno dell'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;
    }
}

Il circuito interno potrebbe essere abbreviato in:

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

In realtà volevo inventarmi questo (come la mia prima risposta qui). L'hai fatto prima, quindi ecco il tuo +1 (per non usare un Regex soggetto a errori)! Suggerimento: è possibile utilizzare uno zoppo 1anziché il trueper la in_arrayricerca rigorosa. Puoi anche omettere le parentesi. Non ne sono del tutto sicuro, ma iirc potresti anche lasciar cadere httpe lasciare solo ://(vai senza lo schema). .
Kaiser

E: Un'altra possibilità sarebbe quella di abbandonare il if ( ) {}favore di in_array() and print $url.PHP_EOL. Ma sì, otterresti un altro +1 (se potessi) per la migliore leggibilità :)
Kaiser

Ho appena provato il tuo esempio e ho ricevuto un errore per gli standard rigorosi (PHP 5.4). Sembra come nella fonte, c'è da qualche parte un collegamento danneggiato o formattato erroneamente con un punto e virgola mancante. È possibile disattivare la segnalazione degli errori utilizzando @\DOMDocument. Ho appena provato e posso confermare che funziona.
Kaiser

No, è la documentazione che è sbagliata; tecnicamente non dovresti chiamare ::loadHTMLFile()staticamente e aggiungere @solo nasconde quel manufatto.
Jack

2
Questa è sicuramente una delle soluzioni più "corrette", una delle uniche che ho potuto vedere in uso in produzione. bel lavoro
Jordon Biondo,

14

Unix Shell

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

Anche se devo ammettere che questo non funziona se c'è più di un collegamento su una linea.


1
curl http://www.stroustrup.com/C++.htmlsalva alcuni personaggi.
l0b0

7
"ma non sono consentite librerie di terze parti" . Immagino che dato che wgetè GNU (come è bash), si potrebbe sostenere che non è di terze parti. Ma curlsicuramente è di terze parti.
Trauma digitale

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

4
@TobiasKienzler Suppongo che il codice originale di Stroustrup non li trovi neanche
Ruslan,

14

Giava

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
Potresti formattare correttamente il codice nelle tue risposte? Non è competizione per il codice meno leggibile. Puoi formattarlo per evitare almeno barre di scorrimento orizzontali.
Athari,

Se usi a Scannerpuoi farlo elaborare il modello regex per i collegamenti direttamente e scorrere Scanneri risultati.
Holger,

5
Sì ... questo è Java per te. Usarlo per il golf del codice è un'impresa coraggiosa.
Javavba,

4
Non avrei mai pensato di vedere una soluzione java in realtà più corta di C ++!
Slebetman

2
Correzione al mio ultimo commento: devo ammettere che questo è praticamente il codice più breve e pulito che può essere scritto in Java. Ho provato un approccio al parser SAX, che potrebbe essere reso ancora più breve con lambdas, ma la pagina web non è XHTML e il parser genera eccezioni. Regex è l'unica strada da percorrere.
Mister Smith,

11

Groovy

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

Potrebbe essere migliorato usando? operatore per evitare NPE?
Chris K,

2
@ChrisKaminski ed essere il primo (accanto a Bjarne) da queste parti per verificare la presenza di errori? mai! a parte questo: vedo solo eccezioni relative all'IO qui. dove vedi un NPE?
cfrick

findAll () potrebbe restituire null, no? O restituirà un elenco vuoto? Ancora un po 'nuovo per Groovy. EDIT: nm, sembra findAll () restituisce un elenco vuoto. Quei ragazzi Groovy erano così intelligenti. :-)
Chris K,

11

SQL (SQL Anywhere 16)

Definire una procedura memorizzata per recuperare la pagina Web

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

Produrre il set di risultati utilizzando una singola query

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;

Limitazioni: produce fino a 256 collegamenti. Se esistono più collegamenti, aumentare il 256 su un valore appropriato.


2
Non credevo che ci sarebbe stato il golf in SQL ... fino ad ora.
vaxquis,

Ho capito ... "link". :-)
Jack al 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
Immagino che questo sia CoffeeScript / Node? Immagino che dovresti specificare che ...
John Dvorak,

Wow. È molto leggibile.
Slebetman,

@slebetman è decisamente piccolo però
John Dvorak l'

@slebetman Yeah CoffeeScript è molto più leggibile di JavaScript :) Sono stato felice di sbarazzarmi di tutte le parentesi graffe} :)
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
Il codice risulterebbe più chiaro se si evitassero le variabili di separatore di campo e di record e si facesse semplicemente: print map {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso,

@DanielRuoso concordato.
primo

o anche use v5.10;e say for $response->content...
Mark Reed l'

A ciascuno il suo, suppongo. Alcune delle funzionalità perl6 backportate sono state problematiche (corrispondenza intelligente, ti sto guardando), ma sayè piuttosto utile e nella mia mente più chiara qui. (Inoltre, ci sono stati un sacco di miglioramenti completamente non correlati al perl6ismo perl5 negli ultimi 13 anni; potrebbe valere la pena di provarlo.)
Mark Reed,

@MarkReed Concordo sul fatto che sayprobabilmente è più leggibile in questo caso, in particolare per quelli che non hanno familiarità con il perl.
primo

9

R

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

... sebbene R sia scritto principalmente in C ... quindi probabilmente alcune righe di codice C dietro quelle 2 righe di codice R.


2
Questo (o qualcosa di simile) è vero per praticamente tutte le risposte qui.
JLRishe

8

Objective-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
Che cosa? Scrivi la versione Swift. Quell'assurdità della parentesi quadra mi fa male agli occhi :)
Signor Smith, l'

2
Evviva per []! Inoltre, dovremmo aggiungere totalmente una versione Smalltalk;)
Bersaelor

La risposta di @MisterSmith Swift è ora disponibile qui .
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]

Puoi scappare facendo http :: data all'interno dei put. Non è necessario creare una variabile temporanea. E lo formattarei anche inserendo nuove righe e rientrando in ciascuno di essi [. Ma questa è una scelta di stile.
Slebetman,

7

Partire

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 questo codice legge l'intera fonte in memoria, quindi considera l'utilizzo regexp.FindReaderIndexdi una ricerca in streaming, che renderà l'app antiproiettile.


6

CJam

CJam non ha regex quindi ho dovuto usare un approccio diverso in questo:

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

Per prima cosa converto tutto 'in ", quindi divido tutto ", prendo ogni stringa alternativa e infine filtra l'elenco per le stringhe che iniziano con http://o https://. Successivamente, stampa semplicemente ogni stringa filtrata su una nuova riga.

Provalo usando l' interprete Java come

java -jar cjam-0.6.2.jar file.cjam

dove file.cjam ha i contenuti del codice sopra.


9
Non so della parte leggibile ... non sapevo che Cjam avesse funzionalità web
Def

Se vuoi giocare a golf ... ''/'"f/:+per ''/'"*'"/'"f/0f=.
jimmy23013,

... aspetta perché '"f/0f=c'è? Dovrebbe fare qualcosa ( 2%per esempio)?
jimmy23013,

6

F #

Questo codice potrebbe essere molto più breve, ma scriverei qualcosa del genere se mi aspettassi di leggere o utilizzare nuovamente questo codice in modo che abbia molte annotazioni di tipo non necessarie. Dimostra l'uso di un patternValue di pattern attivo per abilitare il pattern-matching rispetto al tipo CLR standard 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)

Modifica Ho fatto getLink la sua funzione


Mi piace molto come hai usato le annotazioni dei tipi. Penso che nominare i valori per descrivere ciò che ritorni sia ok, ma il nome della funzione è abbastanza espressivo: getHTML e valore html, getLinks e valore dei collegamenti. Le ultime due righe possono essere link |> Seq.iter (printfn "% s")
MichalMa

@MichalMa Concordo sul fatto che il nome della funzione sia abbastanza espressivo da solo, le variabili html e links sono lì per ragioni pragmatiche: quindi c'è un posto dove impostare un breakpoint. Ho usato il ciclo for invece di List.iter solo perché mi piace il modo in cui legge di più, sebbene in un sostituto probabilmente avrei usato List.iter.
FonteSimian,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.