Debunking Stroustrups Debunking des Mythos "C ++ ist nur für große, komplizierte Programme"

161

Stroustrup hat kürzlich eine Reihe von Posts veröffentlicht, in denen beliebte Mythen über C ++ entlarvt werden . Der fünfte Mythos lautet: „C ++ ist nur für große, komplizierte Programme“. Um es zu entlarven, schrieb er ein einfaches C ++ - Programm, das eine Webseite herunterlud und Links daraus extrahierte . Hier ist es:

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

Zeigen wir Stroustrup, was für ein kleines und lesbares Programm das ist.

  1. Herunterladen http://www.stroustrup.com/C++.html
  2. Alle Links auflisten:

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

Sie können eine beliebige Sprache verwenden, Bibliotheken von Drittanbietern sind jedoch nicht zulässig.

Gewinner

Die C ++ - Antwort, die durch Stimmen gewonnen wurde, basiert auf einer Bibliothek eines halben Drittanbieters (die von den Regeln nicht zugelassen ist) und zusammen mit einem anderen engen Konkurrenten, Bash , auf einem gemeinsam gehackten HTTP-Client (dies funktioniert nicht mit HTTPS). gzip, Weiterleitungen usw.). Damit ist Wolfram ein klarer Sieger. Eine andere Lösung, die in Bezug auf Größe und Lesbarkeit sehr nahe kommt, ist PowerShell (mit Verbesserungen gegenüber Kommentaren), die jedoch nicht viel Aufmerksamkeit erhalten hat. Mainstream-Sprachen ( Python , C # ) kamen auch ziemlich nahe.

Athari
quelle
43
Für jeden Einzelnen wurde ich als schlechter bezeichnet. Wenn es das Ziel des OP nicht wäre, zu versuchen und irgendwie zu beweisen, dass Stroustrup falsch ist, dann würde ich Ihrer Einschätzung zustimmen. Die ganze Prämisse der Frage ist jedoch zu zeigen, wie "Ihre Lieblingssprache" das Gleiche wie diese 50 Zeilen C ++ in viel weniger Codezeilen tun kann. Das Problem ist, dass keines der Beispiele dasselbe tut. Insbesondere führt keine der Antworten eine Fehlerprüfung durch, keine der Antworten bietet wiederverwendbare Funktionen, die meisten Antworten bieten kein vollständiges Programm. Das Stroustrup-Beispiel bietet all das.
Dunk
19
Was traurig ist, ist, dass seine Webseite nicht einmal UTF-8-gültig ist . Jetzt muss ich das umgehen, trotz seiner Serverwerbung Content-Type: text/html; charset=UTF-8... Ich werde ihm eine E-Mail schicken.
Cornstalks
27
@Dunk Die anderen Beispiele bieten keine wiederverwendbaren Funktionen, da sie die gesamte Funktionalität dieser Funktionen in einer einzigen Zeile ausführen. Es macht keinen Sinn, diese Funktion als Ganzes zu definieren, und das C ++ - Beispiel führt keine Fehlerprüfung durch das wird von Haus aus nicht fast identisch gehandhabt, und der Ausdruck "vollständiges Programm" ist fast bedeutungslos.
Jason
16
"Sie können eine beliebige Sprache verwenden, Bibliotheken von Drittanbietern sind jedoch nicht zulässig." Ich glaube nicht , das ist eine faire Anforderung unter Berücksichtigung boost/asioes aufgebraucht ist , was ist eine Drittanbieter - Bibliothek. Ich meine, wie werden Sprachen, die URL / TCP-Abruf als Teil ihrer Standardbibliothek nicht enthalten, konkurrieren?
Urwolf

Antworten:

116

Wolfram

Das fühlt sich an wie völliges Betrügen

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

Fügen Sie einfach ehrliches Parsen hinzu

Cases[
 Import["http://www.stroustrup.com/C++.html", "XMLObject"],
 XMLElement["a", {___, "href" -> link_, ___}, ___] :> 
  link /; StringMatchQ[link, RegularExpression["((http://)?www([./#\\+-]\\w*)+)"]]
, Infinity]
Swish
quelle
49
Nein, ich sehe hier keinen Betrug. Bei dieser Herausforderung geht es darum, das Beste aus Ihrer Sprache herauszuholen. Und diese erste Zeile ist der Inbegriff von "klein und lesbar".
Martin Ender
Eine Antwort, die die albernen Argumente über das Abfangen von FTP-Links ignorieren kann. Brillant.
Seth Battin
Kam hierher, um genau diese Lösung anzubieten, und freute sich zu sehen, dass es auch andere geschätzt haben.
Michael Stern
@ MartinBüttner In diesem Fall sollten Sie meta.codegolf.stackexchange.com/a/1078/12130
David Mulder
6
@DavidMulder Technisch gesehen ist die Lücke derzeit nicht gültig, da die Abstimmungsaufschlüsselung + 41 / -21 beträgt (und die Lückenfrage besagt, dass Lücken akzeptiert werden, wenn es mindestens doppelt so viele positive Stimmen wie negative Stimmen gibt). Zugegebenermaßen ein enger Anruf, aber dennoch. ;) Außerdem handelt es sich um einen Beliebtheitswettbewerb, keinen Codegolf, und insbesondere geht es darum zu zeigen, wie einfach dies in einer bestimmten Sprache getan werden kann, weshalb ich denke, dass die Lücke nicht wirklich gilt diese Herausforderung trotzdem (da die Herausforderung grundsätzlich danach fragt).
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";
}

Das größte Manko ist die peinliche Art von boost :: asio. Ich bin mir sicher, dass es mit einer besseren Bibliothek noch kürzer sein kann.

congusbongus
quelle
166
Komisch, wie "keine Bibliotheken von Drittanbietern" bedeutet, dass Python möglicherweise noch immer import urllib2C3 ist using System.Net, Haskel möglicherweise noch immer import Network.HTTP, aber ein C ++ - Codierer muss Entschuldigungen dafür #include <boost/asio.hpp>vorbringen, als ob er einen metrischen Crapton spezialisierter, zweckgebauter C ++ - (und C!) - Bibliotheken hätte Zur Auswahl steht etwas,
wofür
19
@DevSolar hat beinahe ein zweites Konto erstellt, um Ihnen ein weiteres Plus für diesen Kommentar zu geben
Benutzer
15
@DevSolar System.Netwird nicht erzwungen, es ist nur eine hochwertige Bibliothek, die alle in der Sprache enthaltenen .NET-Empfehlungen befolgt . Es gibt alternative Implementierungen, aber die HTTP-Unterstützung in der Standardbibliothek bedeutet, dass das Schreiben einfacher Apps einfach ist, eine bessere Interoperabilität zwischen Bibliotheken von Drittanbietern bedeutet, weniger Abhängigkeiten, eine einfache Implementierung für Fassaden usw. Stellen Sie sich eine Welt ohne vor std::string, wie jeder sie nutzt Stellen Sie sich alle Schwierigkeiten vor, die damit einhergehen.
Athari
17
@ DevSolar: urllib2ist nicht 3rd Party. Es ist in stdlib wie <iostream>in C ++. urllib2in Python ist im Gegensatz zu C ++ immer verfügbar <boost/asio.hpp>. Wenn wir Module von Drittanbietern verwenden dürften; Ich würde lxmloder BeautifulSoupin Python verwenden.
jfs
22
Außerdem denke ich, dass der wichtigste Kommentar hier nur ist, dass C ++ nicht so viel Material in seinen Standardbibliotheken standardisiert wie in anderen Sprachen, aber es gibt immer noch weit verbreitete robuste portable Bibliotheken für viele der gleichen Aufgaben, die in Sprachen Standard sind wie Python, und einige dieser Bibliotheken sind fast ein De-facto-Standard. Ein Teil davon ist das Ergebnis von C ++, das eingebettete Systeme mit kleinen Binärdateien und kleinen Bibliotheken als Ziel haben kann.
Peter Cordes
85

Pure Bash unter Linux / OS X (keine externen Dienstprogramme)

HTTP-Client-Software ist notorisch aufgebläht. Wir wollen solche Abhängigkeiten nicht. Stattdessen können wir die entsprechenden Header in einem TCP-Stream ablegen und das Ergebnis lesen. Es müssen keine archaischen Hilfsprogramme wie grep oder sed aufgerufen werden, um das Ergebnis zu analysieren.

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 - ich nehme an, es könnte besser lesbar sein ...

Digitales Trauma
quelle
1
Wie dieser, der Unix-Dateihandles für die Pipes verwendet.
Javadba
2
Wow, hätte nie gedacht, dass man das ohne externe Utensilien machen kann. Obwohl es scheint, dass meine Bash 3.2.17 auf LFS ein kleines bisschen veraltet ist, so dass nicht unterstützt mapfile:)
Ruslan
@ Ruslan Yep, mapfilekommt mit Bash 4.x. Dasselbe ist auch mit einer while readSchleife möglich.
Digital Trauma
3
@ Ruslan Ich habe es geändert, while readanstatt mapfile. Tragbarer und lesbarer, denke ich.
Digital Trauma
1
Funktioniert auch unter 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

Lahm, aber funktioniert

eptgrant
quelle
9
Warum nicht viele dieser Anrufe verketten? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Fake Name
13
Es ist kurz, aber es ist nicht idiomatisch (Lesbarkeit zählt in Python)
jfs
24
Hmmm ... wenn mein gesamter Code Fehler wie in diesem Beispiel ignoriert hätte, wären 75% bis 90% meiner Arbeit bereits für jedes Projekt erledigt, an dem ich arbeite.
Dunk
20
@Dunk: Angenommen, das Beispiel hat eine Ausnahme abgefangen (z urlopen(). B. von ). Was sollte es mit einer solchen Ausnahme tun, außer abstürzen und sterben? Wenn es trotzdem abstürzt und stirbt, warum sollte Python nicht einfach das Abstürzen und Sterben bewältigen und die Ausnahmebehandlung ganz weglassen?
Kevin
8
@Dunk: Wenn ich mit jemand anderem waren Python - Code, würde ich viel lieber sie nicht fangen urlopenFehler als (sagen wir) sie fangen und rufen sys.exit("something's borked!"). Wenn sie Letzteres tun, muss ich fangen SystemExit, was nie Spaß macht.
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);
    }
}
Athari
quelle
4
Sie können var htmlund wahrscheinlich verwenden var match, um ein paar Zeichen zu rasieren.
Super am
15
@Superbest Ich kann Namen mit einem einzelnen Zeichen erstellen und die htmlVariable auch ganz entfernen , aber das ist nicht das, wonach ich suche.
Athari
6
@Superbest nicht Code-Golf . : D
Kroltan
5
Nun, es verbessert auch die Lesbarkeit. Gibt es jemals einen Grund, diesen nicht zu verwenden, varwenn sich dies nicht auf die Codesemantik auswirkt?
Superbest
6
@Superbest: "Es verbessert die Lesbarkeit" ist subjektiv. Persönlich denke ich, dass die explizite Angabe des Variablentyps die Lesbarkeit verbessert (normalerweise wie in diesem Code hier). Ich möchte dies jedoch nicht diskutieren. Ich möchte nur darauf hinweisen, dass es alternative Sichtweisen gibt.
Cornstalks
54

"Kein Dritter" ist ein Irrtum

Ich denke, dass die Annahme, dass kein Dritter beteiligt ist, ein Trugschluss ist. Und es ist ein spezifischer Irrtum, der C ++ - Entwickler betrifft, da es so schwierig ist, wiederverwendbaren Code in C ++ zu erstellen. Wenn Sie überhaupt etwas entwickeln, selbst wenn es sich um ein kleines Skript handelt, verwenden Sie immer den wiederverwendbaren Code, der Ihnen zur Verfügung steht.

In Sprachen wie Perl, Python, Ruby (um nur einige zu nennen) ist die Wiederverwendung des Codes eines anderen nicht nur einfach, sondern es ist auch so, wie die meisten Leute den Code die meiste Zeit tatsächlich schreiben.

C ++, mit seinen fast unmöglich zu wartenden kompatiblen ABI-Anforderungen, macht dies zu einer viel härteren Aufgabe. Am Ende haben Sie ein Projekt wie Boost, das eine ungeheure Sammlung von Code darstellt und nur sehr wenig komponierbar ist.

Ein CPAN-Beispiel

Nur zum Spaß finden Sie hier ein CPAN-basiertes Beispiel mit einer korrekten Syntaxanalyse des HTML-Codes, anstatt zu versuchen, Regex zum Parsen des HTML-Codes zu verwenden

#!/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");
Daniel Ruoso
quelle
6
Upvote für den Punkt der 3rd - Party - Libs Adressierung, aber: Mist, macht wieder verwendbaren Code in C ++ ist so einfach kitschig wie in einer anderen Sprache. Das Verwenden und insbesondere das Auffinden von wiederverwendbarem Code ist zwar etwas schwieriger, aber das einzige, was ernsthafte Probleme bereitet , ist das Wiederverwenden kompilierter Artefakte. In interpretierten Sprachen wie Perl usw. ist dies häufig kein Problem.
Martin Ba
4
Um eine Analogie zu erweitern, ist Boost mehr wie CPAN - Pick and Choose. Sie bezeichnen CPAN nicht als "monströses Code-Repository", nur weil es so viele Dinge gibt, die Sie nicht verwenden?
Martin Ba
22
CPAN ist nach jeder vernünftigen Definition dieser vier Wörter ein „monströser Speicherort für Code“.
Jwg
3
@MartinBa Ich bin anderer Meinung, da C ++ eine kompilierte Sprache ist und es erforderlich ist, dass jede ausführbare Datei ihren gesamten Stapel von Abhängigkeiten neu erstellt, da es schwierig ist, die ABI-Kompatibilität aufrechtzuerhalten, was die Wiederverwendbarkeit von Code erheblich behindert. Um eine wiederverwendbare Bibliothek in C ++ zu erstellen, müssen Sie sehr lange dauern, um sicherzustellen, dass Sie sich nicht ständig in ABI-inkompatible Änderungen zwingen.
Daniel Ruoso
6
@MartinBa, weil es unerträglich ist, das gesamte Universum jedes Mal neu aufzubauen, wenn Sie eine einfache Aufgabe implementieren möchten.
Daniel Ruoso
47

UNIX-Shell

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

Findet auch einen ftp://Link :)

Ein anderer Weg, ohne sich auf die ://Syntax zu verlassen:

lynx -dump -listonly http://www.stroustrup.com/C++.html | sed -n 's/^[ 0-9.]\+//p'
Ruslan
quelle
38
Ich kann nicht herausfinden, ob ich +1 geben soll, weil die Verwendung eines Webbrowsers zum Herunterladen einer Webseite das richtige Werkzeug für den Job ist, oder -1, weil die Herausforderung darin besteht, ein Programm für blahblahblah zu schreiben, für das Sie gerade ein Programm aufgerufen haben das prasselnde.
David Richerby
2
Ich denke, es ist besser, Luchs durch Locken oder Wget zu ersetzen. Sie werden häufiger zum Herunterladen einer Webseite verwendet.
Pavel Strakhov
4
@PavelStrakhov Ich entschied mich für Luchs genau, weil es die Links entleeren kann, ohne dass ich etwas Besonderes tue :)
Ruslan
2
@SteveJessop von "special" meine ich eigentlich analysieren oder regexen oder was auch immer. Mit lynx greife ich einfach die Liste der Links heraus (die sich kräuseln und nicht auflisten) und entferne die Nummerierung. Sie können es als Betrug betrachten oder was auch immer, aber ich dachte, es macht Spaß, {das Werkzeug zu verwenden, das fast perfekt das tut, was erforderlich ist}, nur die Ausgabe zu optimieren.
Ruslan
7
msgstr "aber keine Bibliotheken von Drittanbietern sind erlaubt" . Ich behaupte, dass lynxdies in diesem Szenario funktional einer Drittanbieter-Bibliothek entspricht.
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;
}

Dieser Code kann als Benutzerstil verwendet werden, um nur absolute Links auf einer Seite in einer unformatierten Liste anzuzeigen. Möglicherweise funktioniert es nicht richtig, wenn Ihr Browser die Mindestschriftgröße erzwingt.

Es funktioniert korrekt mit http://www.stroustrup.com/C++.html(Anmerkung !importantan background). Um auf anderen Seiten mit mehr Stilen arbeiten zu können, muss diese erweitert werden (mehr Eigenschaften zurücksetzen, Eigenschaften als wichtig markieren usw.).

Alternative Version, die relative Links enthält, mit Ausnahme von Intrapage-Links, die mit Hashes beginnen (sie basieren leider auf einem fest codierten absoluten Link):

* {
  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);
}
Athari
quelle
16
Das ist das Schlimmste, was ich je gesehen habe. +1
Emmett R.
1
Das ist wunderschön und absolut schrecklich. +1
Ricdesi
36

Clojure

(->> (slurp "http://www.stroustrup.com")
     (re-seq #"(?:http://)?www(?:[./#\+-]\w*)+"))
Adam
quelle
28
Schlürfen?! Ich muss Clojure lernen.
11684 08.01.15 Uhr
10
@ 11684 - Clojure hat auch Standardfunktionen namens spit, zipperund lazy-cat... :-)
Bob Jarvis
2
Wow, ich denke, das wird eine späte Neujahrsresolution sein. @ 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))))
Jordon Biondo
quelle
2
Ich bin ein wenig enttäuscht, angesichts der Kompaktheit und hervorragenden Lesbarkeit dieses Codes, dass er nicht mehr Stimmen hat. Gut gemacht.
Spacemoose
28

Scala

"""\"(https?://.*?)\"""".r.findAllIn(scala.io.Source.fromURL("http://www.stroustrup.com/C++.html").mkString).foreach(println)
David Xu
quelle
8
packe alles in eine Zeile - C ++ kann es auch
quetzalcoatl
Was ist ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler
22
@quetzalcoatl - Dies ist ein Ausdruck , nicht nur eine Zeile. Sie können einfach alle Zeilenumbrüche aus dem C ++ - Code löschen, aber das ist nicht dasselbe wie die gesamte Aufgabe in einem einzelnen Ausdruck auszuführen.
DaoWen
4
@DaoWen: Entschuldigung, aber das Starten von expressions-vs-line ist einfach albern. Füge ein paar Funktoren hinzu und C ++ kannst du auch. Aber das ist nur die Frage, welche Bibliotheken als "gewährt" gelten und "keinen Code enthalten". Es ändert nichts an der Tatsache, dass das Packen in eine Zeile die Lesbarkeit beeinträchtigt. Man kann es als einzelnen Ausdruck ruhig halten und es einfach in ein paar Zeilen umformatieren, um viel zu gewinnen und nichts anderes zu verlieren, als die Anzahl der Zeilen. Das ist mein Punkt. Dumme Verpackung - C ++ kann es auch. Wenn jemand aus der "albernen Verpackung" heraus will, sollte er den Code aus Gründen der Lesbarkeit formatieren, nicht aus Gründen der Zeilenanzahl.
Quetzalcoatl
3
@quetzalcoatl Tobias hat den Link nicht dort platziert, damit wir ihm folgen können. Er fragte den Verfasser dieser Antwort, warum es nicht in seinen Ergebnissen war.
JLRishe
25

PHP 5

<?php
preg_match_all('/"(https?:\/\/.*?)"/',file_get_contents('http://www.stroustrup.com/C++.html'),$m);
print_r($m[1]);
David Xu
quelle
5
Vorgeschlagene Änderungen: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(derzeit ein Fehler); entfernen array_unshift($m);(derzeit ein Fehler, den Sie wahrscheinlich array_shiftstattdessen gemeint haben ); print_r($m);print_r($m[1]);(nur die URLs ausgeben).
Primo
fest, danke für deine Eingabe
David Xu
@DavidXu Außer, dass Sie es nicht behoben haben ...?
Shahar,
Jetzt ist es behoben.!
David Xu
25

Power Shell

Textsuche für alle vollqualifizierten URLs (einschließlich JavaScript, CSS usw.):

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

Oder um Links nur in Ankertags abzurufen (einschließlich relativer URLs):

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

Kürzere Versionen von Kommentaren:

(iwr "http://www.stroustrup.com/C++.html").Links.href
(iwr "http://www.stroustrup.com/C++.html").Links.href-match":"
Justin Dunlap
quelle
6
Wenn sich jemand wundert, iwrist ein Alias ​​für Invoke-WebRequest(PS3 +).
Athari
8
Sie könnten das Bestreben von PowerShell, Sammlungen zu reduzieren, missbrauchen und Folgendes tun: (iwr "http://www.stroustrup.com/C++.html").Links.href(oder (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"nur für absolute URIs)
Mathias R. Jessen
1
Das ist ziemlich praktisch!
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]); }
}
Kozzi11
quelle
Um die Liste ähnlich machen zu dem ursprünglichen Beispiel, könnten Sie das Programm der Rohr Ausgang durch | sort | uniqoder stattdessen hinzufügen import std.arrayund ändern Sie die Zeile .filter!("a")){ writeln(_.front[1]); }in diese: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Beachten Sie jedoch, dass ich diesen Code nur ausprobiert habe und nicht bewiesen habe, dass er korrekt oder "idiomatisch" ist. :)
Fr.
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');
});
cPu1
quelle
3
Ich frage mich, ob das require('http').getfunktioniert. Wenn dies der Fall ist, können wir die var-Anweisung verwerfen und eine weitere Zeile kürzen.
Unihedron
@ Unihedro Das tut es.
TimWolla
9
@Unihedro Ja, aber dies ist kein Golfwettbewerb.
cPu1,
Sie müssen keine Erfassungsgruppen verwenden.
Ry
Ich denke, es ist eher JavaScript als ein Framework-Name.
mr5
20

Rubin

require 'net/http'
result = Net::HTTP.get(URI.parse('http://www.stroustrup.com/C++.html'))
result.scan(/"((http)s?://.*?)"/)
Yahor Zhylinski
quelle
1
Ihre Regex wird fehlschlagen, müssen Sie verwenden %r{"(https?://[^"]+)"}. Sie können auch verwenden Net::HTTP.get('www.stroustrup.com', '/C++.html'), um die Anforderung zu verkürzen (und lesbar zu halten). So gesamte Code kann in einer Zeile (wobei es lesbar): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Führen Sie es mit ruby -rnet/httpund Sie brauchen nicht einmal require 'net/http'Leitung.
Hauleth,
20

Haskell

Einige Probleme mit "\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
Vlastachu
quelle
Warum ist der Typ resultexplizit angegeben? Es sollte durch seine Verwendung in vollständig eingeschränkt werden unlines.
John Dvorak
1
Dadurch werden die Regeln ein wenig erweitert, da sie weder im Paket enthalten sind Network.HTTPnoch TextRegex.Posixsind base. (Obwohl sie in der Haskell - Plattform ist, und natürlich auf Hackage, so ...)
nicht mehr drehen counterclockwis
1
@ JanDvorak, ich beginne in Ghci zu schreiben (wahrscheinlich sollte ich es unverändert posten). Aber Ihre Notiz ist relevant, danke.
Vlastachu
@leftaroundabout, wusste es nicht. Es sieht so aus, als hätte ich es nicht geschafft, wenn ich das Basispaket verwendet hätte.
Vlastachu
networkist auch nicht dabei base, also gibt es keine praktische Möglichkeit, es mit nur zu tun base.
Lambda Fairy
18

PHP

Soweit ich das beurteilen kann, kommen die meisten modernen PHP-Installationen mit DOM-Verarbeitung daher. Hier ist eine, die die Anker im HTML-Code tatsächlich durchläuft:

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

Die innere Schleife könnte verkürzt werden auf:

preg_match('~^https?://~', $url = $a->getAttribute('href')) && printf("%s\n", $url);
Jack
quelle
Eigentlich wollte w dies kommen (als meine erste Antwort hier). Sie haben es zuerst getan, also hier ist Ihre +1 (für die Verwendung eines fehleranfälligen Regex)! Hinweis: Sie können für die strenge Suche auch einen Lahmen 1anstelle von verwenden . Sie können die Klammern auch weglassen. Ich bin mir nicht ganz sicher, aber ich kann Sie genauso gut fallen lassen und nur verlassen (ohne das Schema). . truein_arrayhttp://
Kaiser
Und: Eine andere Möglichkeit wäre, das if ( ) {}zugunsten von fallen zu lassen in_array() and print $url.PHP_EOL. Aber ja, Sie würden eine weitere +1 (wenn ich könnte) für die beste Lesbarkeit bekommen :)
Kaiser
Habe gerade dein Beispiel ausprobiert und einen Fehler für strenge Standards erhalten (PHP 5.4). In der Quelle scheint es einen fehlerhaften oder falsch formatierten Link mit einem fehlenden Semikolon zu geben. Sie können die Fehlerberichterstattung mit deaktivieren @\DOMDocument. Habe es gerade versucht und kann bestätigen, dass es funktioniert.
Kaiser
Nein, es ist die Dokumentation, die falsch ist. Technisch gesehen sollten Sie nicht ::loadHTMLFile()statisch aufrufen und @nur das Artefakt ausblenden.
Jack
2
Dies ist definitiv eine der "korrektesten" Lösungen, eine der einzigen, die ich in der Produktion sehen konnte. gute Arbeit
Jordon Biondo
14

Unix-Shell

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

Obwohl ich zugeben muss, dass dies nicht funktioniert, wenn mehr als ein Link in einer Zeile steht.

Guntram Blohm
quelle
1
curl http://www.stroustrup.com/C++.htmlSpeichert ein paar Zeichen.
07.01.15
7
msgstr "aber keine Bibliotheken von Drittanbietern sind erlaubt" . Ich denke, da wgetGNU ist (wie Bash), könnte man argumentieren, dass es nicht von Drittanbietern ist. curlIst aber definitiv Fremdanbieter.
Digital Trauma
Was ist mit ftp://ftp.research.att.com/pub/c++std/WP/CD2und https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler
4
@TobiasKienzler Ich denke, Stroustrup Original-Code findet sie auch nicht
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());
    }
}
David Xu
quelle
3
Könnten Sie den Code in Ihren Antworten richtig formatieren? Es ist kein Wettbewerb um den am wenigsten lesbaren Code. Sie können es formatieren, um zumindest horizontale Bildlaufleisten zu vermeiden.
Athari
Wenn Sie a verwenden Scanner, können Sie festlegen, dass das reguläre Ausdrucksmuster für Links direkt verarbeitet und die ScannerErgebnisse des Objekts durchlaufen werden .
Holger
5
Ja, das ist Java für dich. Es ist ein mutiges Unterfangen, es für Code-Golf zu verwenden.
Javadba
4
Ich hätte nie gedacht, dass ich eine Java-Lösung sehen würde, die tatsächlich kürzer als C ++ ist!
Slebetman
2
Korrektur meines letzten Kommentars: Ich muss zugeben, dass dies so ziemlich der kürzeste und sauberste Code ist, der in Java geschrieben werden kann. Ich habe einen SAX-Parser-Ansatz ausprobiert, der mit Lambdas noch kürzer gemacht werden könnte, aber die Webseite ist nicht XHTML und der Parser löst Ausnahmen aus. Regex ist der einzige Weg.
Mister Smith
11

Groovy

"http://www.stroustrup.com/C++.html".toURL().text.findAll(/https?:\/\/[^"]+/).each{println it}
cfrick
quelle
Könnte durch die Verwendung von verbessert werden? Betreiber NPEs zu vermeiden?
Chris K
2
@ChrisKaminski und als erster (neben Bjarne) hier nach Fehlern suchen? noch nie! daneben sehe ich hier nur IO-bezogene Ausnahmen. Wo siehst du eine NPE?
cfrick
findAll () könnte null zurückgeben, nein? Oder gibt es eine leere Liste zurück? Groovy ist noch ein bisschen neu. EDIT: nm, sieht aus wie findAll () eine leere Liste zurückgibt. Diese Groovy-Typen waren so schlau. :-)
Chris K
11

SQL (SQL Anywhere 16)

Definieren Sie eine gespeicherte Prozedur zum Abrufen der Webseite

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

Erstellen Sie die Ergebnismenge mit einer einzigen Abfrage

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;

Einschränkungen: Dies erzeugt bis zu 256 Links. Wenn weitere Links vorhanden sind, erhöhen Sie die 256 auf einen geeigneten Wert.

Jack bei SAP Canada
quelle
2
Ich habe nicht geglaubt, dass es Golf in SQL geben würde ... bis jetzt.
Vaxquis
Ich verstehe es ... "Links". :-)
Jack bei 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
RobAu
quelle
1
Ich denke das ist CoffeeScript / Node? Ich denke, Sie sollten angeben, dass ...
John Dvorak
Beeindruckend. Das ist sehr gut lesbar.
Slebetman
@slebetman es ist auf jeden Fall klein, aber
John Dvorak
@slebetman Yeah CoffeeScript ist so viel besser lesbar als JavaScript :) Ich war froh, alle geschweiften Klammern loszuwerden} :)
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;
primo
quelle
1
Der Code wäre klarer, wenn Sie die Variablen "Feldtrenner" und "Datensatztrenner" vermeiden und Folgendes tun würden: print map {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso
@DanielRuoso stimmte zu.
Primo
oder sogar use v5.10;und say for $response->content...
Mark Reed
Ich nehme an, jeder für sich. Einige der zurückportierten Perl6-Funktionen waren problematisch (Smart Matching, ich schaue Sie an), aber sie saysind sehr nützlich und meiner Meinung nach hier klarer. (Außerdem wurden in den letzten 13 Jahren ziemlich viele Verbesserungen an Perl5 vorgenommen, die nichts mit Perl6ismus zu tun haben. Es könnte sich lohnen, dies zu überprüfen.)
Mark Reed
@MarkReed Ich stimme zu, dass saydies in diesem Fall wahrscheinlich besser lesbar ist, insbesondere für diejenigen, die mit Perl weniger vertraut sind.
Primo
9

R

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

... obwohl R hauptsächlich in C geschrieben ist ... also wahrscheinlich ein paar Zeilen C-Code hinter diesen 2 Zeilen R-Code.

Rusan Kax
quelle
2
Das (oder etwas Ähnliches) gilt für so ziemlich alle Antworten hier.
JLRishe
8

Ziel 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]]);
}
David Xu
quelle
3
Was? Bitte schreiben Sie die Swift-Version. Dieser Unsinn mit der eckigen Klammer tut meinen Augen weh :)
Mister Smith
2
Hurra für []! Außerdem sollten wir eine Smalltalk-Version hinzufügen;)
Bersaelor
@MisterSmith Schnelle Antwort jetzt hier verfügbar .
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]
Damkerng T.
quelle
Sie können entkommen, indem Sie http :: data in den Puts ausführen. Es muss keine temporäre Variable erstellt werden. Und ich formatiere es auch, indem ich Zeilenumbrüche und Einrückungen an jeder Stelle vornehme [. Aber das ist eine Stilwahl.
Slebetman
7

Gehen

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: Dieser Code liest die gesamte Quelle in den Speicher ein. Verwenden Sie daher die Option regexp.FindReaderIndex, um im Stream zu suchen, damit die App kugelsicher ist.

Maxim Kupriianov
quelle
6

CJam

CJam hat keinen regulären Ausdruck, daher musste ich in diesem einen anderen Ansatz verwenden:

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

Ich konvertiere zuerst alles 'in ", teile dann alles auf ", nehme jede alternative Zeichenfolge und filtere diese Liste schließlich nach Zeichenfolgen, die mit http://oder beginnen https://. Danach drucken Sie einfach jede gefilterte Zeichenfolge in eine neue Zeile.

Probieren Sie es mit dem Java-Interpreter wie

java -jar cjam-0.6.2.jar file.cjam

Dabei hat file.cjam den Inhalt des obigen Codes.

Optimierer
quelle
9
Keine Ahnung von dem lesbaren Teil ... wusste nicht, dass Cjam Web-Funktionalität hat
Def
Wenn Sie es Golf spielen wollen ... ''/'"f/:+für ''/'"*'"/'"f/0f=.
Jimmy23013
... warte, warum ist '"f/0f=da? Soll das ( 2%zum Beispiel) etwas bewirken?
Jimmy23013
6

F #

Dieser Code könnte viel kürzer sein, aber ich würde so etwas schreiben, wenn ich jemals erwartet hätte, diesen Code wieder lesen oder verwenden zu müssen, damit er viele unnötige Typanmerkungen enthält. Es wird die Verwendung eines aktiven Muster- MatchValue demonstriert , um das Muster-Matching gegen den Standard-CLR-Typ Match zu ermöglichen

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)

Edit Ich habe getLinks zu einer eigenen Funktion gemacht

SourceSimian
quelle
Mir gefällt sehr gut, wie Sie Typanmerkungen verwendet haben. Ich denke, Werte zu benennen, um zu beschreiben, was Sie zurückgeben, ist in Ordnung, aber der Name der Funktion ist aussagekräftig genug: getHTML- und html-Wert, getLinks und links-Wert. Die letzten beiden Zeilen können Links sein. |> Seq.iter (printfn "% s")
MichalMa
@MichalMa Ich bin damit einverstanden, dass der Name der Funktion für sich genommen aussagekräftig genug ist. Die Variablen html und links gibt es aus pragmatischen Gründen: Es gibt also einen Ort, an dem ein Haltepunkt gesetzt werden kann. Ich habe die for-Schleife anstelle von List.iter verwendet, nur weil ich die Art und Weise mag, in der es mehr liest, obwohl ich in einer Antwort wahrscheinlich List.iter verwendet hätte.
SourceSimian