Desacreditando el mito de Stroustrup: "C ++ es solo para programas grandes y complicados"


161

Stroustrup ha publicado recientemente una serie de publicaciones que desacreditan mitos populares sobre C ++ . El quinto mito es: "C ++ es solo para programas grandes y complicados". Para desacreditarlo, escribió un sencillo programa en C ++ que descarga una página web y extrae enlaces de ella . Aquí está:

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

using namespace std;

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

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

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

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

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

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

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

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

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

Vamos a mostrarle a Stroustrup qué es un programa pequeño y legible .

  1. Descargar http://www.stroustrup.com/C++.html
  2. Listar todos los enlaces:

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

Puede usar cualquier idioma, pero no se permiten bibliotecas de terceros.

Ganador

La respuesta de C ++ ganada por votos, pero se basa en una biblioteca de terceros (que no está permitida por las reglas) y, junto con otro competidor cercano, Bash , se basa en un cliente HTTP pirateado (no funcionará con HTTPS, gzip, redirecciones, etc.). Entonces Wolfram es un claro ganador. Otra solución que se acerca en términos de tamaño y legibilidad es PowerShell (con la mejora de los comentarios), pero no ha recibido mucha atención. Los lenguajes convencionales ( Python , C # ) también se acercaron bastante.


43
A cada uno lo suyo, me han llamado peor. Si el objetivo del OP no era intentar probar de alguna manera que Stroustrup está equivocado, entonces estaría de acuerdo con su evaluación. Pero la premisa completa de la pregunta es mostrar cómo "su lenguaje favorito" puede hacer lo mismo que estas 50 líneas de C ++ en muchas menos líneas de código. El problema es que ninguno de los ejemplos hace lo mismo. En particular, ninguna de las respuestas realiza ninguna comprobación de errores, ninguna de las respuestas proporciona funciones reutilizables, la mayoría de las respuestas no proporcionan un programa completo. El ejemplo de Stroustrup proporciona todo eso.
Dunk

19
Lo triste es que su página web ni siquiera es válida UTF-8 . Ahora tengo que solucionar eso, a pesar de la publicidad de su servidor Content-Type: text/html; charset=UTF-8... Voy a enviarle un correo electrónico.
Cornstalks

27
@Dunk Los otros ejemplos no proporcionan funciones reutilizables porque logran la funcionalidad completa de esas funciones en una sola línea y no tiene sentido hacer que una función completa por sí sola, y el ejemplo de C ++ no realiza ninguna comprobación de errores eso no se maneja de forma nativa de manera casi idéntica, y la frase "programa completo" es casi sin sentido.
Jason

16
"Puede usar cualquier idioma, pero no se permiten bibliotecas de terceros". No creo que sea un requisito justo teniendo en cuenta que boost/asiose usa allí, que es una biblioteca de terceros. Quiero decir, ¿cómo competirán los idiomas que no incluyen la obtención de url / tcp como parte de su biblioteca estándar?
greatwolf

Respuestas:


116

Wolfram

Esto se siente como una trampa completa

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

Así que solo agrega un análisis honesto en la parte superior

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

49
No, no veo trampas aquí. Este desafío se trata de sacar lo mejor de tu idioma. Y esa primera línea es el epítome de "pequeño y legible".
Martin Ender

Una respuesta que puede ignorar los argumentos tontos sobre la captura de enlaces ftp. Brillante.
Seth Battin

Vine aquí para ofrecer esta solución exacta, me alegra ver que otros también la han apreciado.
Michael Stern el

@ MartinBüttner En ese caso, es posible que desee considerar el voto negativo meta.codegolf.stackexchange.com/a/1078/12130
David Mulder el

66
@DavidMulder Técnicamente, el vacío legal no es válido actualmente, ya que el desglose de votos es + 41 / -21 (y la pregunta del vacío legal dice que se aceptan vacíos legales si hay al menos el doble de votos positivos que votos negativos). Una llamada cercana, es cierto, pero aún así. ;) Además, este es un concurso de popularidad, no un código de golf, y en particular, es un pop-con sobre mostrar cuán fácilmente se puede hacer en un idioma dado, por lo que creo que la laguna no se aplica realmente a este desafío de todos modos (ya que el desafío básicamente lo pide).
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";
}

La principal deficiencia es la naturaleza incómoda de boost :: asio, estoy seguro de que puede ser aún más corto con una mejor biblioteca.


166
Es curioso cómo "no hay bibliotecas de terceros" significa que Python aún puede import urllib2, C3 aún puede ser using System.Net, Haskel aún puede import Network.HTTP, pero un codificador de C ++ debe dar excusas #include <boost/asio.hpp>como si tuviera un crapton métrico de bibliotecas especializadas de C ++ (y C). disponible para elegir es algo de lo que avergonzarse solo porque el comité no se molestó en alimentarlo a la fuerza con uno específico ...
DevSolar

19
@DevSolar estuvo a punto de crear una segunda cuenta para darle otro voto a favor para ese comentario
usuario

15
@DevSolar System.Netno es forzado, es solo una biblioteca de alta calidad que sigue todas las recomendaciones de .NET incluidas con el lenguaje. Hay implementaciones alternativas, pero tener soporte HTTP en la biblioteca estándar significa que escribir aplicaciones simples es simple, significa una mejor interoperabilidad entre bibliotecas de terceros, significa menos dependencias, significa una fácil implementación para fachadas, etc. Imagine un mundo sin std::string, imagine cómo todos usan su propia biblioteca, imagina todas las dificultades que vienen con ella.
Athari

17
@DevSolar: nourllib2 es un tercero. Está en stdlib como <iostream>en C ++. urllib2en Python siempre está disponible a diferencia <boost/asio.hpp>de C ++. Si se nos permitiera usar módulos de terceros; Yo usaría lxmlo BeautifulSoupen Python.
jfs

22
Además, creo que el comentario más importante aquí es solo que C ++ no estandariza tantas cosas en sus bibliotecas estándar como otros lenguajes, pero todavía hay bibliotecas portátiles robustas ampliamente utilizadas para muchas de las mismas tareas que son estándar en lenguajes como Python, y algunas de estas bibliotecas son casi un estándar de facto. Y algo de esto es el resultado de que C ++ puede apuntar a sistemas embebidos con pequeños binarios y pequeñas bibliotecas.
Peter Cordes

85

Pure Bash en Linux / OS X (sin utilidades externas)

El software de cliente HTTP está notoriamente inflado. No queremos ese tipo de dependencias. En su lugar, podemos empujar los encabezados apropiados hacia abajo en una secuencia TCP y leer el resultado. No es necesario llamar a servicios arcaicos como grep o sed para analizar el resultado.

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

Meh: supongo que podría ser más legible ...


1
Al igual que este, que utiliza identificadores de archivos Unix para las tuberías.
Java

2
Wow, nunca pensé que se podía hacer esto sin utilidades externas. Aunque parece que mi bash 3.2.17 en LFS es un poco obsoleto, por lo que no es compatible mapfile:)
Ruslan

@Ruslan Sí, mapfileviene con bash 4.x. Lo mismo es totalmente factible con un while readbucle también.
Trauma digital

3
@Ruslan Lo cambié a en while readlugar de mapfile. Más portátil y más legible, creo.
Trauma digital

1
¡Funciona también en 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

Cojo, pero funciona


99
¿Por qué no encadenar muchas de esas llamadas? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Nombre falso

13
Es corto pero no es idiomático (la legibilidad cuenta en Python)
jfs

24
Hmmm ... si todo mi código ignora errores como este ejemplo, entonces el 75% al ​​90% de mi trabajo ya estaría hecho en cada proyecto en el que trabajo.
Dunk

20
@Dunk: Supongamos que el ejemplo captó alguna excepción (por ejemplo, de urlopen()). ¿Qué debería hacer con tal excepción, aparte de estrellarse y morir? Si se va a estrellar y morir de todos modos, ¿por qué no dejar que Python se encargue de los accidentes y las muertes, y dejar de lado el manejo de excepciones?
Kevin

8
@Dunk: Si estuviera usando el código Python de otra persona, preferiría que no detectaran urlopenerrores que (digamos) los atrapen y llamen sys.exit("something's borked!"). Si hacen lo último, tengo que atraparlo SystemExit, lo cual nunca es divertido.
Kevin

55

C#

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

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

44
Puede usar var html, y probablemente var matchpara afeitarse algunos caracteres.
Excelente

15
@Superbest Puedo hacer nombres de un solo carácter y deshacerme de la htmlvariable por completo también, pero no es lo que busco.
Athari

66
@ Superbest no code-golf . : D
Kroltan

55
Bueno, también mejora la legibilidad. ¿Hay alguna razón para no usar varcuando no afectará la semántica del código?
Excelente

66
@Superbest: "mejora la legibilidad" es subjetiva. Personalmente, creo que establecer explícitamente el tipo de la variable mejora la legibilidad (generalmente, como en este código aquí). Sin embargo, no quiero debatir esto; Solo quiero señalar que existen puntos de vista alternativos.
Cornstalks

54

"Ningún tercero" es una falacia

Creo que la suposición de "no terceros" es una falacia. Y es una falacia específica que afecta a los desarrolladores de C ++, ya que es muy difícil crear código reutilizable en C ++. Cuando desarrolle algo, incluso si se trata de un script pequeño, siempre utilizará las piezas de código reutilizables disponibles.

La cuestión es que, en lenguajes como Perl, Python, Ruby (por nombrar algunos), reutilizar el código de otra persona no solo es fácil, sino que es cómo la mayoría de las personas realmente escriben código la mayor parte del tiempo.

C ++, con sus requisitos ABI casi imposibles de mantener, hace que sea un trabajo mucho más difícil, terminas con un proyecto como Boost, que es un depósito monstruoso de código y muy poca compostura fuera de él.

Un ejemplo de CPAN

Solo por diversión, aquí va un ejemplo basado en CPAN, con el análisis adecuado del html, en lugar de tratar de usar regex para analizar 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");

66
Voto por abordar el punto de las librerías de terceros, pero: mierda, hacer que el código reutilizable en C ++ sea tan fácil como en otro lenguaje. Utilizando y sobre todo encontrar reutilizable código puede ser un poco más difícil, pero la única cosa que es seriamente problemático es la reutilización compilados artefactos, pero que a menudo no sea un problema en lenguajes interpretados como Perl, etc
Martin Ba

44
Para estirar una analogía, Boost es más como CPAN: elige y elige. ¿No llamas a CPAN un "depósito monstruoso de código" solo porque hay muchas cosas allí que no usas?
Martin Ba

22
CPAN es un "depósito monstruoso de código", por cualquier definición razonable de esas cuatro palabras.
jwg

3
@MartinBa No estoy de acuerdo, ya que C ++ es un lenguaje compilado, que requiere que cada ejecutable reconstruya su pila completa de dependencias porque es difícil mantener la compatibilidad ABI dificulta seriamente la reutilización del código. Para producir una biblioteca reutilizable en C ++, debe pasar por largos tramos muy largos para asegurarse de no forzarse a realizar cambios incompatibles con ABI todo el tiempo.
Daniel Ruoso

66
@MartinBa porque tener que reconstruir todo el universo cada vez que quieres implementar una tarea simple es insoportable.
Daniel Ruoso

47

Shell de UNIX

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

También encuentra un ftp://enlace :)

Otra forma, sin depender de la ://sintaxis:

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

38
No puedo determinar si hacer +1 porque usar un navegador web para descargar una página web es la herramienta adecuada para el trabajo o -1 porque el desafío es escribir un programa para hacer blahblahblah y acabas de llamar a un programa para hacer el blahing
David Richerby

2
Creo que es mejor reemplazar lynx con curl o wget. Se usan más comúnmente para descargar una página web.
Pavel Strakhov

44
@PavelStrakhov Elegí Lynx exactamente porque puede volcar los enlaces sin que yo haga nada especial :)
Ruslan

2
@SteveJessop por "especial" me refiero a en realidad analizar o regexing o lo que sea. Con lynx simplemente elimino la lista de enlaces (que curl y wget no enumeran) y elimino la numeración. Puede considerarlo hacer trampa o lo que sea, pero pensé que es divertido {utilizar la herramienta que hace casi perfectamente lo que se requiere}, simplemente ajustando la salida.
Ruslan

77
"pero no se permiten bibliotecas de terceros" . Sostengo que lynxes funcionalmente equivalente a una biblioteca de terceros en este escenario.
Trauma digital el

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

Este código puede usarse como un estilo de usuario para mostrar solo enlaces absolutos en una página en una lista sin formato. Es posible que no funcione correctamente si su navegador exige un tamaño de fuente mínimo.

Funciona correctamente con http://www.stroustrup.com/C++.html(nota !importantsobre background). Para trabajar en otras páginas con más estilos, debe ampliarse (restablecer más propiedades, marcar propiedades como importantes, etc.).

Versión alternativa que incluye enlaces relativos, excepto los enlaces intrapágina que comienzan con hashes (lamentablemente, se basa en un enlace absoluto codificado):

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

16
Esto es lo peor que he visto. +1
Emmett R.

1
Esto es hermoso y completamente horrible. +1
ricdesi

36

Clojure

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

28
¡¿Sorber?! Necesito aprender Clojure.
11684

10
@ 11684 - Clojure también tiene funciones estándar nombradas spit, zippery lazy-cat... :-)
Bob Jarvis

2
Wow, creo que será una Resolución de Año Nuevo tardía. @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
Estoy un poco decepcionado, dado lo compacto y eminentemente legible que es este código, que no tiene más votos. Bien hecho.
Spacemoose

28

Scala

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

8
empacar todo en una línea - C ++ también puede hacerlo
quetzalcoatl

¿Qué hay de ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl: esta es una expresión , no solo una línea. Simplemente puede eliminar todos los saltos de línea del código C ++, pero eso no es lo mismo que hacer toda la tarea en una sola expresión.
DaoWen

44
@DaoWen: Lo siento, pero comenzar expresiones-vs-line se está volviendo tonto. Agregue algunos functores y C ++ también puede hacerlo. Pero esa es solo la cuestión de qué bibliotecas se consideran "otorgadas" y tienen "código cero adentro". No cambia el hecho de que empaquetarlo en una línea impida la legibilidad. Uno puede mantenerlo quieto como una sola expresión y simplemente formatearlo en unas pocas líneas para ganar mucho y perder nada más que ... recuento de líneas. Ese es mi punto. Embalaje tonto: C ++ también puede hacerlo. Si alguien quiere salir de la caja de "embalaje tonto", debe formatear el código para facilitar la lectura, no para el recuento de líneas.
quetzalcoatl

3
@quetzalcoatl Tobias no puso el enlace allí para que lo sigamos. Le preguntaba al escritor de esta respuesta por qué no estaba en sus resultados.
JLRishe

25

PHP 5

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

55
Ediciones sugeridas: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(actualmente un error); eliminar array_unshift($m);(actualmente es un error, probablemente quisiste decirlo en su array_shiftlugar); print_r($m);print_r($m[1]);(solo genera las URL).
primo

arreglado, gracias por tu aporte
David Xu

@DavidXu ¿Excepto que no lo arreglaste ...?
Shahar

ahora está arreglado.
David Xu

25

Potencia Shell

Búsqueda de texto para todas las URL totalmente calificadas (incluidos JavaScript, CSS, etc.):

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

O para obtener enlaces solo en etiquetas de anclaje (incluye URL relativas):

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

Versiones más cortas de los comentarios:

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

66
Si alguien se pregunta, iwres un alias para Invoke-WebRequest(PS3 +).
Athari

8
Podrías abusar del afán de PowerShell de aplanar colecciones y hacer: (iwr "http://www.stroustrup.com/C++.html").Links.href(o (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"solo para URIs absolutos)
Mathias R. Jessen

1
Eso es muy útil!
Justin Dunlap

22

re

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

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

Para que la lista similar a la original ejemplo, usted podría tubería de salida del programa a través de | sort | uniqo en lugar añadir import std.arrayy cambiar la línea .filter!("a")){ writeln(_.front[1]); }en esto: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Sin embargo, tenga en cuenta que solo he probado este código y no he demostrado que sea correcto o "idiomático". :)
Viernes

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
Me pregunto si require('http').getfunciona. Si es así, podemos deshacernos de la declaración var y acortar otra línea.
Unihedron

@Unihedro lo hace.
TimWolla

99
@Unihedro Sí, pero este no es un concurso de golf.
cPu1

No necesita utilizar ningún grupo de captura.
Ry-

Creo que es JavaScript en lugar de un nombre de marco.
mr5

20

Rubí

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

1
Tu expresión regular fallará, debes usarla %r{"(https?://[^"]+)"}. También puede usar Net::HTTP.get('www.stroustrup.com', '/C++.html')para acortar la solicitud (y mantenerla legible). Así código entero puede estar en una línea (manteniéndolo legible): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Ejecútelo ruby -rnet/httpy ni siquiera necesita require 'net/http'línea.
Hauleth

20

Haskell

Algunos problemas con "\w"en Text.Regex.Posix

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

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

¿Por qué se resultespecifica el tipo de explícitamente? Debe estar completamente limitado por su uso en unlines.
John Dvorak

1
Esto estirar un poco las reglas, ya que ninguno Network.HTTP, ni TextRegex.Posixestán en el basepaquete. (Aunque están en la Plataforma Haskell, y por supuesto en Hackage, así que ...)
dejó de girar en sentido contrario a las agujas del reloj el

1
@ JanDvorak, empiezo a escribir en ghci (probablemente debería publicarlo sin cambios). Pero tu nota es relevante, gracias.
vlastachu

@leftaroundabout, no lo sabía. Parece que no podría haberlo hecho si hubiera usado el paquete base.
vlastachu

networkno está en baseninguno de los dos, así que ahorre para enrollar sus propios enlaces de socket, no hay una forma práctica de hacerlo con solo base.
Lambda Fairy

18

PHP

Por lo que puedo decir, la mayoría de las instalaciones PHP modernas vienen con procesamiento DOM, así que aquí hay una que realmente atraviesa los anclajes dentro del 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;
    }
}

El circuito interno podría acortarse a:

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

En realidad quería aparecer con esto (como mi primera respuesta aquí). Lo hiciste primero, ¡así que aquí está tu +1 (por no usar una expresión regular propensa a errores)! Sugerencia: podría usar un cojo en 1lugar de truepara la in_arraybúsqueda estricta. También puede omitir los corchetes. No estoy completamente seguro, pero iirc también podría soltar el httpy solo dejar el ://(ir sin el esquema). .
kaiser

Y: Otra posibilidad sería dejar caer if ( ) {}a favor de in_array() and print $url.PHP_EOL. Pero sí, obtendrías otro +1 (si pudiera) para una mejor legibilidad :)
kaiser

Acabo de probar su ejemplo y obtuve un error de estándares estrictos (PHP 5.4). Parece que en la fuente, hay un enlace dañado o formateado incorrectamente con un punto y coma faltante. Puede desactivar el informe de errores mediante el uso @\DOMDocument. Solo intenté eso y puedo confirmar que funciona.
kaiser

No, es la documentación lo que está mal; técnicamente no debes llamar ::loadHTMLFile()estáticamente, y agregar @solo oculta ese artefacto.
Jack

2
Esta es definitivamente una de las soluciones más "correctas", una de las únicas que pude ver en uso en la producción. buen trabajo
Jordon Biondo

14

Unix Shell

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

Aunque tengo que admitir que esto no funciona si hay más de un enlace en una línea.


1
curl http://www.stroustrup.com/C++.htmlGuarda algunos caracteres.
l0b0

77
"pero no se permiten bibliotecas de terceros" . Supongo que dado que wgetes GNU (como es bash), se podría argumentar que no es un tercero. Pero curldefinitivamente es un tercero.
Trauma digital

¿Qué hay de ftp://ftp.research.att.com/pub/c++std/WP/CD2y https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

44
@TobiasKienzler Supongo que el código original de Stroustrup tampoco los encuentra
Ruslan

14

Java

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

3
¿Podría formatear correctamente el código en sus respuestas? No es competencia por el código menos legible. Puede formatearlo para evitar al menos las barras de desplazamiento horizontales.
Athari

Si usa un Scanner, puede hacer que procese el patrón regex para enlaces directamente e iterar sobre los Scannerresultados de.
Holger

55
Sí ... eso es Java para ti. Usarlo para el golf de código es una empresa valiente.
Java

44
¡Nunca pensé que vería una solución Java que en realidad sea más corta que C ++!
slebetman

2
Corrección a mi último comentario: debo admitir que este es el código más corto y más limpio que se puede escribir en Java. He intentado un enfoque de analizador SAX, que podría hacerse aún más corto con lambdas, pero la página web no es XHTML y el analizador arroja excepciones. Regex es el único camino a seguir.
Señor Smith el

11

Maravilloso

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

¿Podría mejorarse usando? operador para evitar NPE?
Chris K

2
@ChrisKaminski y ser el primero (junto a Bjarne) por aquí para verificar si hay errores? ¡Nunca! además de eso: solo veo excepciones relacionadas con IO aquí. ¿Dónde ves un NPE?
cfrick

findAll () podría devolver nulo, ¿no? ¿O devolverá una lista vacía? Todavía un poco nuevo para Groovy. EDITAR: nm, parece que findAll () devuelve una lista vacía. Esos tipos Groovy eran muy inteligentes. :-)
Chris K

11

SQL (SQL en cualquier lugar 16)

Definir un procedimiento almacenado para recuperar la página web.

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

Produzca el conjunto de resultados usando una sola consulta

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

Limitaciones: Esto produce hasta 256 enlaces. Si existen más enlaces, suba el 256 a un valor apropiado.


2
No creía que hubiera golf en SQL ... hasta ahora.
vaxquis

Lo entiendo ... "enlaces". :-)
Jack en SAP Canadá

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
Supongo que esto es CoffeeScript / Node? Supongo que deberías especificar eso ...
John Dvorak

Guau. Eso es muy legible.
slebetman

@slebetman definitivamente es pequeño, sin embargo
John Dvorak

@slebetman Yeah CoffeeScript es mucho más legible que JavaScript :) Me alegré de deshacerme de todas las llaves} :)
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
El código sería más claro si evitara las variables de separador de campo y de separador de registros y simplemente hiciera: print map {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso

@DanielRuoso estuvo de acuerdo.
primo

o incluso use v5.10;y say for $response->content...
Mark Reed

A cada uno lo suyo, supongo. Algunas de las características de perl6 con respaldo han sido problemáticas (coincidencia inteligente, te estoy mirando), pero sayes bastante útil y, en mi opinión, más claro aquí. (Además, ha habido muchas mejoras completamente no relacionadas con el perl6ismo en perl5 en los últimos 13 años; podría valer la pena echarle un vistazo.)
Mark Reed

@ MarkReed Estoy de acuerdo en que sayprobablemente sea más legible en este caso, particularmente para aquellos menos familiarizados con Perl.
primo

9

R

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

... aunque R está escrito principalmente en C ... así que probablemente unas pocas líneas de código C detrás de esas 2 líneas de código R.


2
Eso (o algo similar) es cierto para casi todas las respuestas aquí.
JLRishe

8

C objetivo

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
¿Qué? Por favor escriba la versión Swift. Esa tontería entre corchetes me está lastimando los ojos :)
Señor Smith

2
¡Hurra por []! Además, deberíamos agregar totalmente una versión Smalltalk;)
Bersaelor

La respuesta de @MisterSmith Swift ahora está disponible aquí .
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]

Puede escapar haciendo http :: data dentro de los Put. No es necesario crear una variable temporal. Y también lo formatearía poniendo nuevas líneas y sangría en cada [. Pero esa es una elección de estilo.
slebetman

7

Ir

package main

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

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

PD: este código lee toda la fuente en la memoria, así que considera usarlo regexp.FindReaderIndexpara buscar en stream, eso hará que la aplicación sea a prueba de balas.


6

CJam

CJam no tiene expresiones regulares, así que tuve que usar un enfoque diferente en este:

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

Primero convierto todo 'a ", luego me divido en todos ", tomo cada cadena alternativa y finalmente filtro esa lista para las cadenas que comienzan con http://o https://. Después de eso, simplemente imprima cada cadena filtrada en una nueva línea.

Pruébelo utilizando el intérprete de Java como

java -jar cjam-0.6.2.jar file.cjam

donde file.cjam tiene el contenido del código anterior.


99
No sé sobre la parte legible ... no sabía que Cjam tiene funcionalidad web
Def

Si quieres jugar al golf ... ''/'"f/:+para ''/'"*'"/'"f/0f=.
jimmy23013

... espera ¿por qué '"f/0f=hay? ¿Se supone que eso debe hacer algo ( 2%por ejemplo)?
jimmy23013

6

F#

Este código podría ser mucho más corto, pero escribiría algo como esto si alguna vez esperaba tener que leer o usar este código nuevamente, por lo que tiene muchas anotaciones de tipo innecesarias. Demuestra el uso de un patrón MatchValue activo para permitir la coincidencia de patrones con el tipo estándar CLR Match

open System.Net

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

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

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

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

Editar hice que getLinks tenga su propia función


Realmente me gusta cómo usaste anotaciones de tipo. Creo que nombrar valores para describir lo que devuelve está bien, pero el nombre de la función es lo suficientemente expresivo: valor getHTML y html, valor getLinks y enlaces. Las dos últimas líneas pueden ser enlaces |> Seq.iter (printfn "% s")
MichalMa

@MichalMa Estoy de acuerdo en que el nombre de la función es lo suficientemente expresivo por sí solo, las variables html y links están ahí por razones pragmáticas: por lo tanto, hay un lugar para establecer un punto de interrupción. Usé el bucle for en lugar de List.iter solo porque me gusta la forma en que lee más, aunque en una respuesta probablemente hubiera usado List.iter.
SourceSimian
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.