Dissociation du mythe par Stroustrup: «Le C ++ est réservé aux grands programmes compliqués»


161

Stroustrup a récemment publié une série de messages qui réfutent les mythes populaires sur le C ++ . Le cinquième mythe est le suivant: «C ++ s’applique uniquement aux grands programmes compliqués». Pour le démystifier, il a écrit un simple programme C ++ téléchargeant une page Web et en extrayant des liens . C'est ici:

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

Montrons à Stroustrup ce qu'est un petit programme lisible .

  1. Télécharger http://www.stroustrup.com/C++.html
  2. Lister tous les liens:

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

Vous pouvez utiliser n'importe quelle langue, mais aucune bibliothèque tierce n'est autorisée.

Gagnant

La réponse C ++ a été remportée par un vote, mais elle repose sur une bibliothèque semi-tierce (interdite par les règles) et, avec un autre concurrent proche, Bash , sur un client HTTP piraté (cela ne fonctionnera pas avec HTTPS, gzip, redirections, etc.). Donc, Wolfram est un gagnant clair. Une autre solution qui se rapproche du point de vue de la taille et de la lisibilité est PowerShell (avec une amélioration par rapport aux commentaires), mais elle n’a pas suscité beaucoup d’attention. Les langages traditionnels ( Python , C # ) sont également très proches.


43
À chacun ses goûts, on m'a appelé pire. Si l'objectif de l'OP n'était pas d'essayer de prouver d'une manière ou d'une autre que Stroustrup avait tort, je serais d'accord avec votre évaluation. Mais la prémisse de la question est de montrer comment "votre langue préférée" peut faire la même chose que ces 50 lignes de C ++ en beaucoup moins de lignes de code. Le problème est qu'aucun des exemples ne fait la même chose. En particulier, aucune des réponses ne vérifie les erreurs, aucune ne fournit de fonctions réutilisables, la plupart des réponses ne fournissent pas un programme complet. L'exemple Stroustrup fournit tout cela.
Dunk

19
Ce qui est triste, c'est que sa page Web n'est même pas valide en UTF-8 . Maintenant, je dois contourner ce problème, malgré la publicité de son serveur Content-Type: text/html; charset=UTF-8... Je vais lui envoyer un courriel.
Corn Stalks

27
@Dunk Les autres exemples ne fournissent pas de fonctions réutilisables, car ils réalisent toute la fonctionnalité de ces fonctions sur une seule ligne. Cela n'a aucun sens de créer une fonction complète et l'exemple C ++ n'effectue aucune vérification d'erreur. cela n'est pas géré de manière native de manière presque identique, et l'expression "programme complet" n'a presque aucun sens.
Jason

16
"Vous pouvez utiliser n’importe quelle langue, mais aucune bibliothèque tierce n’est autorisée." Je ne pense pas que ce soit une exigence juste compte boost/asioest utilisé là - bas qui est une bibliothèque tiers. Je veux dire, comment les langues qui n'incluent pas l'extraction url / tcp dans le cadre de sa bibliothèque standard entrent-elles en concurrence?
Grand

Réponses:


116

Wolfram

Cela ressemble à de la triche complète

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

Il suffit donc d'ajouter une analyse honnête sur le dessus

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

49
Non, je ne vois pas de tricherie ici. Ce défi consiste à faire ressortir le meilleur de votre langue. Et cette première ligne est l'incarnation de "petit et lisible".
Martin Ender

Une réponse qui peut ignorer les arguments stupides sur la capture des liens FTP. Brillant.
Seth Battin

Venu ici pour offrir cette solution exacte, heureux de voir que d’autres l’ont également appréciée.
Michael Stern

@ MartinBüttner Dans ce cas, vous pouvez envisager de voter à la baisse meta.codegolf.stackexchange.com/a/1078/12130
David Mulder

6
@DavidMulder Techniquement, l'échappatoire n'est actuellement pas valide, puisque la répartition des voix est de + 41 / -21 (et la question relative aux échappatoires stipule que les échappatoires sont acceptées s'il y a au moins deux fois plus de votes positifs que de votes négatifs). Un appel proche, certes, mais quand même. ;) En outre, il s’agit d’un concours de popularité, et non d’un code de golf, et en particulier d’une explication évidente de la facilité avec laquelle cela peut être fait dans une langue donnée, c’est pourquoi je pense que l’échappatoire ne s’applique pas vraiment à ce défi quand même (puisque le défi le demande fondamentalement).
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";
}

Le principal inconvénient est la nature délicate de boost :: asio, je suis sûr que cela peut être encore plus court avec une meilleure bibliothèque.


166
C'est drôle comme "pas de librairies tierces" veut dire que Python peut quand même import urllib2, C3 peut être encore using System.Net, Haskel peut encore import Network.HTTP, mais un codeur C ++ doit trouver des excuses pour avoir le même sens #include <boost/asio.hpp>que s'il avait un métrique de bibliothèques C ++ (et C!) Spécialisées, spécialement conçues à cet effet. il est honteux de pouvoir choisir parmi les choix disponibles simplement parce que le comité n'a pas pris la peine de vous gaver de force ...
DevSolar 8/08

19
@DevSolar a failli créer un deuxième compte pour vous donner un autre vote positif pour ce commentaire
utilisateur du

15
@DevSolar System.Netn'est pas forcé, c'est juste une bibliothèque de haute qualité qui respecte toutes les recommandations .NET incluses dans le langage. Il existe d’autres implémentations, mais le support HTTP dans la bibliothèque standard signifie que l’écriture d’applications simples est simple, elle permet une meilleure interopérabilité entre les bibliothèques tierces, moins de dépendances, une implémentation facile pour les façades, etc. Imaginez un monde sans std::string, imaginez comment tout le monde utilise leur propre bibliothèque, imaginez toutes les difficultés qui vont avec.
Athari

17
@ DevSolar: urllib2n'est pas une 3ème partie. C'est dans stdlib comme <iostream>en C ++. urllib2en Python est toujours disponible contrairement <boost/asio.hpp>à C ++. Si nous étions autorisés à utiliser des modules tiers; Je voudrais utiliser lxmlou BeautifulSoupen Python.
Jfs

22
De plus, je pense que le commentaire le plus important ici est simplement que le C ++ ne standardise pas autant de choses dans ses bibliothèques standard que dans les autres langages, mais qu'il existe encore des bibliothèques portables robustes largement utilisées pour de nombreuses tâches identiques aux standards dans les langages. comme python, et certaines de ces bibliothèques sont presque une norme de facto. Et une partie de cela est due au fait que C ++ peut cibler des systèmes incorporés avec de petits binaires et de petites bibliothèques.
Peter Cordes

85

Pure Bash sous Linux / OS X (pas d'utilitaire externe)

Le logiciel client HTTP est notoirement gonflé. Nous ne voulons pas de ce genre de dépendances. Au lieu de cela, nous pouvons insérer les en-têtes appropriés dans un flux TCP et lire le résultat. Nul besoin d'appeler des utilitaires archaïques comme grep ou sed pour analyser le résultat.

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 - Je suppose que ça pourrait être plus lisible ...


1
Comme celui-ci utilisant des descripteurs de fichiers unix pour les pipes.
javadba

2
Wow, jamais pensé on peut le faire sans utils externes. Bien qu'il semble que mon bash 3.2.17 sur LFS soit un peu obsolète, il ne supporte donc pas mapfile:)
Ruslan

@Ruslan Yep, mapfilevient avec bash 4.x. La même chose est tout à fait faisable avec une while readboucle.
Digital Trauma

3
@Ruslan je l'ai changé au while readlieu de mapfile. Plus portable et plus lisible, je pense.
Digital Trauma

1
Fonctionne aussi sur 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, mais fonctionne


9
Pourquoi ne pas enchaîner beaucoup de ces appels? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Faux nom

13
C'est court mais ce n'est pas idiomatique (la lisibilité compte en Python)
jfs

24
Hmmm ... si tout mon code ignorait les erreurs comme cet exemple, 75% à 90% de mon travail serait déjà effectué sur chaque projet sur lequel je travaille.
Dunk

20
@Dunk: Supposons que l'exemple attrape une exception (par exemple de urlopen()). Que devrait-il faire d'une telle exception, à part le crash et la mort? Si cela devait se bloquer et mourir de toute façon, pourquoi ne pas simplement laisser Python gérer le crash et la mort, et laisser de côté la gestion des exceptions?
Kevin

8
@Dunk: Si j'utilisais le code Python de quelqu'un d'autre, je préférerais de beaucoup qu'il ne détecte pas les urlopenerreurs plutôt que (par exemple) les rattraper et les appeler sys.exit("something's borked!"). S'ils font ce dernier, je dois attraper SystemExit, ce qui n'est jamais amusant.
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
Vous pouvez utiliser var htmlet probablement var matchraser quelques personnages.
Superbest

15
@Superbe, je peux créer des noms avec un seul caractère et me débarrasser des htmlvariables, mais ce n'est pas ce que je recherche.
Athari

6
@Superbest pas le code-golf . : D
Kroltan

5
Eh bien, cela améliore aussi la lisibilité. Y a-t-il une raison de ne pas utiliser varquand cela n'aura pas d'impact sur la sémantique du code?
Superbest

6
@Superbest: "cela améliore la lisibilité" est subjectif. Personnellement, je pense qu'énoncer explicitement le type de la variable améliore la lisibilité (généralement, comme dans ce code ici). Je ne veux pas en débattre, cependant; Je veux juste souligner qu'il existe des points de vue différents.
Cornstalks

54

"Pas de tiers" est une erreur

Je pense que l'hypothèse "pas de tierce partie" est une erreur. Et est une erreur spécifique qui afflige les développeurs C ++, car il est si difficile de créer du code réutilisable en C ++. Lorsque vous développez quelque chose que ce soit, même s'il s'agit d'un petit script, vous utiliserez toujours les morceaux de code réutilisables qui vous sont disponibles.

Le fait est que, dans des langages comme Perl, Python, Ruby (pour n'en nommer que quelques-uns), la réutilisation du code de quelqu'un d'autre est non seulement facile, mais permet également à la plupart des gens d'écrire du code la plupart du temps.

C ++, avec ses exigences ABI compatibles presque impossibles à maintenir, rend ce travail beaucoup plus difficile, vous vous retrouvez avec un projet comme Boost, qui est un immense dépôt de code et une très faible composabilité en dehors de celui-ci.

Un exemple de CPAN

Juste pour le plaisir, voici un exemple basé sur CPAN, avec une analyse syntaxique correcte du html, au lieu d’ essayer d’utiliser regex pour analyser 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
Upvote pour aborder le point des bibliothèques tierces, mais: merde, faire du code réutilisable en C ++ est aussi facile cheesy que dans un autre langage. Utiliser et surtout trouver du code réutilisable peut être un peu plus difficile, mais la seule chose qui pose problème, c'est de réutiliser des artefacts compilés , mais c'est souvent un problème dans les langages interprétés comme Perl, etc.
Martin Ba

4
Pour étirer une analogie, Boost ressemble plus à CPAN - choisissez et choisissez. Vous n'appelez pas CPAN un "référentiel monstrueux de code" juste parce qu'il y a tant de choses que vous n'utilisez pas?
Martin Ba

22
CPAN est un «référentiel monstrueux de code», selon toute définition raisonnable de ces quatre mots.
Jwg

3
@MartinBa Je ne suis pas d'accord, le langage C ++ étant un langage compilé, nécessitant que chaque exécutable reconstruise sa pile de dépendances car il est difficile de maintenir la compatibilité ABI, ce qui entrave considérablement la réutilisation du code. Pour produire une bibliothèque réutilisable en C ++, vous devez effectuer des tâches très longues afin de vous assurer que vous ne vous forcez pas tout le temps à des modifications incompatibles avec ABI.
Daniel Ruoso

6
@MartinBa, car il est insupportable de devoir reconstruire l'univers entier à chaque fois que vous souhaitez implémenter une tâche simple.
Daniel Ruoso

47

Shell UNIX

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

Trouve également un ftp://lien :)

Une autre façon, sans compter sur la ://syntaxe:

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

38
Je ne sais pas s'il faut utiliser +1 pour télécharger une page Web à l'aide d'un navigateur Web, ni pour -1 parce que le défi consiste à écrire un programme pour faire blahblahblah et vous venez d'appeler un programme pour le faire. le bla
David Richerby le

2
Je pense qu'il est préférable de remplacer le lynx par curl ou wget. Ils sont plus couramment utilisés pour télécharger une page Web.
Pavel Strakhov

4
@PavelStrakhov J'ai choisi Lynx exactement parce qu'il peut vider les liens sans que je fasse quoi que ce soit de spécial :)
Ruslan

2
@SteveJessop par "spécial" Je veux dire réellement analyser ou regexing ou autre chose. Avec Lynx, je viens de supprimer la liste des liens (que curl et wget ne listent pas) et de supprimer la numérotation. Vous pouvez envisager de tricher ou peu importe, mais j'ai trouvé amusant de {utiliser l'outil qui fait presque parfaitement ce qui est requis}, en affinant simplement le résultat.
Ruslan

7
"mais aucune bibliothèque tierce n'est autorisée" . Je soutiens que cela lynxcorrespond fonctionnellement à une bibliothèque tierce dans ce scénario.
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;
}

Ce code peut être utilisé comme style utilisateur pour afficher uniquement les liens absolus sur une page dans une liste non formatée. Il risque de ne pas fonctionner correctement si votre navigateur impose une taille de police minimale.

Cela fonctionne correctement avec http://www.stroustrup.com/C++.html(note !importantsur background). Pour pouvoir travailler sur d'autres pages avec plus de styles, il doit être étendu (réinitialiser davantage de propriétés, marquer les propriétés comme importantes, etc.).

Version alternative qui inclut des liens relatifs sauf les liens intrapage commençant par des hachages (elle repose malheureusement sur un lien absolu codé en dur):

* {
  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
C'est la pire chose que j'ai jamais vue. +1
Emmett R.

1
C'est magnifique et complètement horrible. +1
ricdesi

36

Clojure

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

28
Slurp?! J'ai besoin d'apprendre Clojure.
11684

10
@ 11684 - Clojure a également des fonctions standard nommées spit, zipperet lazy-cat... :-)
Bob Jarvis

2
Wow, je pense que ça va être une résolution tardive du nouvel an. @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
Je suis un peu déçu, vu la compacité et la lisibilité de ce code, de ne pas avoir plus de votes. Bien joué.
Spacemoose

28

Scala

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

8
emballer tout en une ligne - C ++ peut le faire aussi
quetzalcoatl

Qu'en est- il ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl - Ceci est une expression , pas une seule ligne. Vous pouvez simplement supprimer tous les sauts de ligne du code C ++, mais ce n'est pas la même chose que de faire toute la tâche dans une seule expression.
DaoWen

4
@ DaoWen: Désolé, mais démarrer expressions-vs-line est simplement ridicule. Ajoutez quelques foncteurs et C ++, vous pouvez le faire aussi. Mais c'est juste la question de savoir quelles bibliothèques sont considérées comme "accordées" et ont "zéro code à l'intérieur". Cela ne change pas le fait que le compresser dans une ligne rende la lisibilité impossible. On peut le garder comme une seule expression et le reformater en quelques lignes pour gagner beaucoup et ne rien perdre que le nombre de lignes. C'est mon point. Emballage idiot - C ++ peut le faire aussi. Si quelqu'un veut sortir de la boîte "d'emballage stupide", alors formatez le code pour le rendre lisible, pas linecount.
Quetzalcoatl

3
@quetzalcoatl Tobias n'a pas mis le lien là pour que nous puissions le suivre. Il demandait à l'auteur de cette réponse pourquoi ce n'était pas dans ses résultats.
JLRishe

25

PHP 5

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

5
Modifications suggérées: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(actuellement une erreur); remove array_unshift($m);(actuellement une erreur, vous vouliez probablement dire à la array_shiftplace); print_r($m);print_r($m[1]);(ne sortir que les URL).
Primo

corrigé, merci pour votre contribution
David Xu

@ DavidXu Sauf que vous n'avez pas résolu le problème ...?
Shahar

maintenant sa fixée.!
David Xu

25

PowerShell

Recherche de texte pour toutes les URL entièrement qualifiées (y compris JavaScript, CSS, etc.):

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

Ou pour obtenir des liens dans les balises d'ancrage uniquement (inclut les URL relatives):

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

Des versions plus courtes des commentaires:

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

6
Si quelqu'un se demande, iwrest un alias pour Invoke-WebRequest(PS3 +).
Athari

8
Vous pouvez abuser de l’empressement de PowerShell d’aplatir les collections et faire: (iwr "http://www.stroustrup.com/C++.html").Links.href(ou (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"uniquement pour les
Mathias R. Jessen

1
C'est très pratique!
Justin Dunlap

22

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

Pour la liste semblable à l'exemple d' origine, vous pouvez tuyau de sortie du programme par le biais | sort | uniqou au lieu d' ajouter import std.arrayet de modifier la ligne .filter!("a")){ writeln(_.front[1]); }dans ce: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Notez, cependant, que j'ai seulement essayé ce code et que je n'ai pas prouvé qu'il était correct ou "idiomatique". :)
vendredi

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
Je me demande si ça require('http').getmarche. Si c'est le cas, nous pouvons abandonner l'instruction var et raccourcir une autre ligne.
Unihedron

@Unihedro C'est le cas.
TimWolla

9
@Unihedro C'est le cas, mais ce n'est pas un concours de golf.
cPu1

Vous n'avez pas besoin d'utiliser de groupes de capture.
Ry-

Je pense que c'est JavaScript plutôt qu'un nom de cadre.
mr5

20

Rubis

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

1
Votre regex va échouer, vous devez utiliser %r{"(https?://[^"]+)"}. Vous pouvez également utiliser Net::HTTP.get('www.stroustrup.com', '/C++.html')pour raccourcir la demande (et la garder lisible). Ainsi , le code entier peut être dans une ligne (garder lisible): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Exécutez-le avec ruby -rnet/httpet vous n'avez même pas besoin de require 'net/http'ligne.
Hauleth

20

Haskell

Quelques problèmes avec "\w"dans 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

Pourquoi le type de resultspécifié explicitement? Il devrait être entièrement contraint par son utilisation dans unlines.
John Dvorak

1
Cela étire un peu les règles, vu que ni dans l' emballage, Network.HTTPni TextRegex.Posixdans l' baseemballage. (Bien qu'ils soient dans la plate-forme Haskell, et bien sûr sur Hackage, alors ...)
cessé de tourner en contre-la-montre le

1
@JanDvorak, je commence à écrire en ghci (je devrais probablement le poster sans modification). Mais votre note est pertinente, merci.
mardi

@leftaroundabout, ne savait pas. Il semble que je n'aurais pas pu le faire si j'avais utilisé le paquet de base.
mardi

networkest pas basenon plus , donc économiser pour rouler vos propres liaisons socket il n'y a aucun moyen pratique de le faire avec juste base.
Lambda Fairy

18

PHP

Autant que je sache, la plupart des installations PHP modernes intègrent un traitement DOM. En voici donc une qui traverse les ancres à l'intérieur du code 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;
    }
}

La boucle interne pourrait être réduite à:

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

En fait, je voulais y aller (comme ma première réponse ici). Vous l'avez fait en premier, alors voici votre +1 (pour ne pas utiliser une Regex sujette aux erreurs)! Astuce: Vous pouvez utiliser une lame 1au lieu de la truepour la in_arrayrecherche stricte. Vous pouvez également omettre les crochets. Je ne suis pas tout à fait sûr, mais vous pourriez aussi bien laisser tomber le bouton httpet le laisser ://(ne pas utiliser le système). .
Kaiser

Et: une autre possibilité serait de laisser tomber if ( ) {}en faveur de in_array() and print $url.PHP_EOL. Mais oui, vous auriez un autre +1 (si je pouvais) pour une meilleure lisibilité :)
kaiser

Juste essayé votre exemple et obtenu une erreur pour les normes strictes (PHP 5.4). On dirait que dans la source, il y a quelque part un lien corrompu ou mal formaté avec un point-virgule manquant. Vous pouvez désactiver le rapport d'erreur en utilisant @\DOMDocument. Je viens d’essayer ça et je peux confirmer que ça marche.
Kaiser

Nah, c'est la documentation qui est fausse; techniquement, vous n'êtes pas censé appeler ::loadHTMLFile()statiquement et ajouter @uniquement les peaux à cet artefact.
Jack

2
C’est définitivement l’une des solutions les plus "correctes", l’une des seules que je pouvais utiliser en production. bon travail
Jordon Biondo

14

Unix Shell

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

Bien que je dois admettre que cela ne fonctionne pas s'il y a plus d'un lien sur une ligne.


1
curl http://www.stroustrup.com/C++.htmlenregistre quelques caractères.
l0b0

7
"mais aucune bibliothèque tierce n'est autorisée" . Je suppose que puisque wgetGNU (comme Bash) est bas, vous pourriez dire que ce n’est pas une tierce partie. Mais curlest définitivement tiers.
Digital Trauma

Qu'en est-il ftp://ftp.research.att.com/pub/c++std/WP/CD2et https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

4
@TobiasKienzler J'imagine que le code original de Stroustrup ne les trouve pas non plus
Ruslan le

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
Pourriez-vous formater correctement le code dans vos réponses? Ce n'est pas une concurrence pour le code le moins lisible. Vous pouvez le formater pour éviter au moins les barres de défilement horizontales.
Athari

Si vous utilisez a, Scannervous pouvez lui demander de traiter directement le motif de regex pour les liens et de parcourir les Scannerrésultats.
Holger

5
Oui… c'est java pour vous. Son utilisation pour le golf de code est une entreprise courageuse.
javadba

4
Je n'aurais jamais pensé voir une solution Java plus courte que le C ++!
Slebetman

2
Correction de mon dernier commentaire: je dois admettre que c’est à peu près le code le plus court et le plus propre qui puisse être écrit en Java. J'ai essayé une approche par analyseur SAX, qui pourrait être encore plus courte avec lambdas, mais la page Web n'est pas en XHTML et l'analyseur génère des exceptions. Regex est le seul moyen d'y aller.
Monsieur Smith le

11

Sensationnel

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

Pourrait être amélioré en utilisant? opérateur pour éviter les NPE?
Chris K

2
@ChrisKaminski et soyez le premier (à côté de Bjarne) ici pour vérifier les erreurs? jamais! à côté de cela: je ne vois que les exceptions liées à l'IO ici. Où voyez-vous un NPE?
cfrick

findAll () peut renvoyer null, non? Ou retournera-t-il une liste vide? Encore un peu nouveau pour Groovy. EDIT: nm, on dirait que findAll () renvoie une liste vide. Ces gars Groovy étaient si intelligents. :-)
Chris K

11

SQL (SQL Anywhere 16)

Définir une procédure stockée pour récupérer la page Web

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

Produire le jeu de résultats en utilisant une seule requête

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;

Limitations: Cela produit jusqu'à 256 liens. Si plus de liens existent, alors remplacez le 256 par une valeur appropriée.


2
Je ne croyais pas qu'il y aurait du golf en SQL ... jusqu'à maintenant.
vaxquis

Je comprends ... "liens". :-)
Jack chez SAP Canada le

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
Je suppose que c'est CoffeeScript / Node? J'imagine que vous devriez préciser que ...
John Dvorak

Sensationnel. C'est très lisible.
Slebetman

@slebetman c'est vraiment petit cependant
John Dvorak

@slebetman Yeah CoffeeScript est tellement plus lisible que JavaScript :) J'étais heureux de me débarrasser de toutes les accolades} :)
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
Le code serait plus clair si vous évitiez les variables séparateur de champs et séparateur d’enregistrements et que vous veniez de faire: print map {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso

@ DanielRuoso a accepté.
primo

ou même use v5.10;et say for $response->content...
Mark Reed le

À chacun ses goûts, je suppose. Certaines des fonctionnalités de perl6 gérées par l'arrière sont problématiques (correspondance intelligente, je vous regarde), mais elles saysont très utiles et, à mon avis, plus claires ici. (En outre, perl5 a connu de nombreuses améliorations au cours des 13 dernières années; elles mériteraient sans doute d'être vérifiées.)
Mark Reed Le

@ MarkReed Je conviens que sayc'est probablement plus lisible dans ce cas, en particulier pour ceux qui sont moins familiers avec perl.
Primo

9

R

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

... bien que R soit écrit principalement en C ... donc probablement quelques lignes de code C derrière ces 2 lignes de code R.


2
Cela (ou quelque chose de similaire) est vrai pour à peu près toutes les réponses ici.
JLRishe

8

Objectif 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
Quelle? S'il vous plaît écrivez la version Swift. Ce non-sens entre crochets me fait mal aux yeux :)
Mister Smith

2
Vive le []! Aussi, nous devrions ajouter totalement une version Smalltalk;)
Bersaelor le

La réponse de @MisterSmith Swift est maintenant disponible ici .
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]

Vous pouvez vous échapper en faisant http :: data dans les options de vente. Pas besoin de créer une variable temporaire. Et je le formaterais aussi en mettant des nouvelles lignes et des retraits à chaque fois [. Mais c'est un choix de style.
Slebetman

7

Aller

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: ce code lit l'intégralité de la source en mémoire, pensez donc à utiliser la regexp.FindReaderIndexrecherche en flux pour rendre l'application à l'épreuve des balles.


6

CJam

CJam n'a pas de regex et j'ai donc dû utiliser une approche différente dans celle-ci:

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

Je convertis d'abord tout 'en ", puis je divise tout ", je prends chaque chaîne alternative et enfin filtre cette liste pour les chaînes commençant par http://ou https://. Ensuite, imprimez simplement chaque chaîne filtrée sur une nouvelle ligne.

Essayez-le en utilisant l' interpréteur Java comme

java -jar cjam-0.6.2.jar file.cjam

où fichier.cjam a le contenu du code ci-dessus.


9
Je ne sais pas pour la partie lisible ... je ne savais pas que Cjam avait une fonctionnalité Web
Def le

Si vous voulez jouer au golf ... ''/'"f/:+pour ''/'"*'"/'"f/0f=.
jimmy23013

... attends pourquoi est- '"f/0f=il? Est-ce censé faire quelque chose ( 2%par exemple)?
jimmy23013

6

F#

Ce code pourrait être beaucoup plus court, mais j'écrirais quelque chose comme ceci si je m'attendais à devoir lire ou utiliser à nouveau ce code afin qu'il contienne de nombreuses annotations de type inutiles. Il illustre l'utilisation d'un modèle actif MatchValue pour permettre la correspondance de modèle avec le type de 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)

Edit j'ai fait à getLinks sa propre fonction


J'aime beaucoup la façon dont vous avez utilisé les annotations de type. Je pense que nommer des valeurs pour décrire ce que vous retournez est correct, mais le nom de la fonction est assez expressif: getHTML et la valeur html, getLinks et la valeur des liens. Les deux dernières lignes peuvent être des liens |> Seq.iter (printfn "% s")
Michalma

@ MichalMa Je conviens que le nom de la fonction est assez expressif, les variables html et links sont présentes pour des raisons pragmatiques: il existe donc un endroit pour définir un point d'arrêt. J'ai utilisé la boucle for au lieu de List.iter simplement parce que j'aime la façon dont elle se lit plus, bien que dans une réplique j'aurais probablement utilisé List.iter.
SourceSimian
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.