Obalanie Obalenie przez Stroustrupa mitu „C ++ jest tylko dla dużych, skomplikowanych programów”

161

Stroustrup opublikował ostatnio serię postów obalających popularne mity o C ++ . Piąty mit brzmi: „C ++ jest przeznaczony tylko dla dużych, skomplikowanych programów”. Aby go obalić, napisał prosty program C ++ pobierający stronę internetową i wydobywający z niej linki . Oto on:

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

Pokażmy Stroustrupowi, czym tak naprawdę jest mały i czytelny program.

  1. Pobieranie http://www.stroustrup.com/C++.html
  2. Wyświetl wszystkie linki:

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

Możesz używać dowolnego języka, ale biblioteki innych firm nie są dozwolone.

Zwycięzca

Odpowiedź C ++ wygrana głosami, ale opiera się ona na bibliotece innej firmy (która jest niedozwolona przez zasady), a wraz z innym bliskim konkurentem Bashem opiera się na zhakowanym kliencie HTTP (nie będzie współpracować z HTTPS, gzip, przekierowania itp.). Więc Wolfram jest wyraźnym zwycięzcą. Kolejnym rozwiązaniem, które jest bardzo podobne pod względem wielkości i czytelności, jest PowerShell (z ulepszeniami wynikającymi z komentarzy), ale nie spotkał się on z dużym zainteresowaniem. Języki głównego nurtu ( Python , C # ) również były bardzo podobne.

Athari
źródło
43
Do każdego własnego nazywano mnie gorszym. Jeśli celem PO nie była próba udowodnienia, że ​​Stroustrup się myli, zgodziłbym się z twoją oceną. Ale cała przesłanka tego pytania polega na pokazaniu, w jaki sposób „Twój ulubiony język” może zrobić to samo, co 50 linii C ++ w znacznie mniejszej liczbie wierszy kodu. Problem polega na tym, że żaden z przykładów nie robi tego samego. W szczególności żadna z odpowiedzi nie sprawdza błędów, żadna z odpowiedzi nie udostępnia funkcji wielokrotnego użytku, większość odpowiedzi nie zapewnia pełnego programu. Przykład Stroustrup zapewnia to wszystko.
Dunk
19
Smutne jest to, że jego strona internetowa nie jest nawet poprawna UTF-8 . Teraz muszę to obejść, pomimo jego reklam na serwerze Content-Type: text/html; charset=UTF-8... Wyślę mu e-maila.
Cornstalks
27
@Dunk Pozostałe przykłady nie zawierają funkcji wielokrotnego użytku, ponieważ realizują one całą funkcjonalność tych funkcji w jednym wierszu i nie ma sensu tworzyć całej tej funkcji samodzielnie, a przykład w C ++ nie wykonuje żadnego sprawdzania błędów nie jest to obsługiwane natywnie w prawie identyczny sposób, a zwrot „kompletny program” jest prawie bez znaczenia.
Jason
16
„Możesz używać dowolnego języka, ale biblioteki innych firm nie są dozwolone”. Nie sądzę, że to sprawiedliwe wymaganie rozważa boost/asiostosowany jest tam, który jest biblioteką trzeciej. Mam na myśli, w jaki sposób konkurować będą języki, które nie obejmują pobierania adresów URL / TCP jako części standardowej biblioteki?
greatwolf

Odpowiedzi:

115

Wolfram

To jest jak całkowite oszustwo

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

Więc po prostu dodaj uczciwe parsowanie na wierzchu

Cases[
 Import["http://www.stroustrup.com/C++.html", "XMLObject"],
 XMLElement["a", {___, "href" -> link_, ___}, ___] :> 
  link /; StringMatchQ[link, RegularExpression["((http://)?www([./#\\+-]\\w*)+)"]]
, Infinity]
śmigać
źródło
49
Nie, nie widzę tutaj żadnego oszukiwania. Wyzwanie polega na wydobyciu tego, co najlepsze w Twoim języku. I ta pierwsza linia jest uosobieniem „małego i czytelnego”.
Martin Ender,
Odpowiedź, która może zignorować głupie argumenty na temat łapania łączy ftp. Znakomity.
Seth Battin
Przybyliśmy tutaj, aby zaoferować to dokładne rozwiązanie, ciesząc się, że inni też to docenili.
Michael Stern
@ MartinBüttner W takim przypadku możesz rozważyć rezygnację z głosowania na meta.codegolf.stackexchange.com/a/1078/12130
David Mulder
6
@DavidMulder Technicznie rzecz biorąc, luka nie jest obecnie ważna, ponieważ podział głosów wynosi + 41 / -21 (a pytanie o lukę stwierdza, że ​​luki są akceptowane, jeśli jest co najmniej dwa razy więcej głosów pozytywnych niż głosów negatywnych). Co prawda bliskie połączenie, ale jednak. ;) Co więcej, jest to konkurs popularności, a nie golf golfowy, a w szczególności pop-con pokazujący, jak łatwo można to zrobić w danym języku, dlatego myślę, że luka tak naprawdę nie dotyczy to wyzwanie i tak (ponieważ wyzwanie w zasadzie o to prosi).
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";
}

Główną wadą jest niezręczna natura boost :: asio, jestem pewien, że może być jeszcze krótsza z lepszą biblioteką.

congusbongus
źródło
166
Zabawne, że „brak bibliotek stron trzecich” oznacza, że ​​Python może nadal import urllib2, C3 może nadal using System.Net, Haskel może nadal import Network.HTTP, ale koder C ++ musi usprawiedliwiać, #include <boost/asio.hpp>jak gdyby posiadał metryczny crapton specjalistycznych, specjalnie zbudowanych bibliotek C ++ (i C!) dostępne do wyboru to coś, czego można się wstydzić tylko dlatego, że komitet nie zadał sobie trudu, aby nakarmić cię konkretnym ...
DevSolar
19
@DevSolar prawie poszedł na utworzenie drugiego konta, aby dać ci kolejną opinię o tym komentarzu
użytkownik
15
@DevSolar System.Netnie jest wymuszony, to tylko wysokiej jakości biblioteka zgodna ze wszystkimi zaleceniami .NET zawartymi w tym języku. Istnieją alternatywne implementacje, ale obsługa HTTP w standardowej bibliotece oznacza, że ​​pisanie prostych aplikacji jest proste, oznacza lepszą interoperacyjność między bibliotekami stron trzecich, oznacza mniej zależności, oznacza łatwą implementację fasad itp. Wyobraź sobie świat bez std::string, wyobraź sobie, jak wszyscy używają ich własną bibliotekę, wyobraź sobie wszystkie związane z tym trudności.
Athari
17
@DevSolar: nieurllib2 jest stroną trzecią. Jest w stdlib jak w C ++. w Pythonie jest zawsze dostępne inaczej niż w C ++. Gdybyśmy mogli używać modułów zewnętrznych; Chciałbym użyć lub w Pythonie. <iostream>urllib2<boost/asio.hpp>lxmlBeautifulSoup
jfs
22
Myślę też, że najważniejszym komentarzem jest to, że C ++ nie standaryzuje tyle rzeczy w swoich standardowych bibliotekach, co inne języki, ale wciąż istnieją szeroko stosowane solidne przenośne biblioteki do wielu takich samych zadań, które są standardowe w językach jak python, a niektóre z tych bibliotek są prawie de facto standardem. A niektóre z nich są wynikiem tego, że C ++ może atakować systemy osadzone za pomocą małych plików binarnych i małych bibliotek.
Peter Cordes,
85

Pure Bash w systemie Linux / OS X (bez narzędzi zewnętrznych)

Oprogramowanie klienckie HTTP jest notorycznie nadęte. Nie chcemy tego rodzaju zależności. Zamiast tego możemy przesunąć odpowiednie nagłówki w dół strumienia TCP i odczytać wynik. Nie trzeba wywoływać archaicznych narzędzi, takich jak grep lub sed, aby przeanalizować wynik.

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 - przypuszczam, że może być bardziej czytelny ...

Cyfrowa trauma
źródło
1
Tak jak ten, używając uchwytów plików unixowych dla potoków.
javadba
2
Wow, nigdy nie myślałem, że można to zrobić bez zewnętrznych narzędzi. Chociaż wydaje się, że mój bash 3.2.17 na LFS jest trochę przestarzały, więc to nie obsługuje mapfile:)
Ruslan
@ Ruslan Tak, mapfilepochodzi z bash 4.x. To samo jest całkowicie wykonalne z while readpętlą.
Cyfrowa trauma
3
@ Ruslan Zmieniłem go na while readzamiast mapfile. Myślę, że bardziej przenośny i czytelniejszy.
Cyfrowa trauma
1
Działa również na 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

Kulawy, ale działa

eptgrant
źródło
9
Dlaczego nie połączyć wielu takich połączeń? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Fałszywe imię
13
Jest krótki, ale nie jest idiomatyczny (czytelność liczy się w Pythonie)
jfs
24
Hmmm ... jeśli cały mój kod zignoruje błędy takie jak ten przykład, to 75% do 90% mojej pracy byłoby już wykonane na każdym projekcie, nad którym pracuję.
Dunk
20
@Dunk: Załóżmy, że przykład przechwycił jakiś wyjątek (np. Z urlopen()). Co powinien zrobić z takim wyjątkiem oprócz awarii i śmierci? Jeśli i tak się zawiesi i umrze, dlaczego po prostu nie pozwolić Pythonowi uporać się z awarią i umrzeć i całkowicie zrezygnować z obsługi wyjątków?
Kevin
8
@Dunk: Gdybym używał cudzego kodu Python, wolałbym, żeby nie wychwytywał urlopenbłędów niż (powiedzmy) łapał je i dzwonił sys.exit("something's borked!"). Jeśli zrobią to drugie, muszę złapać SystemExit, co nigdy nie jest zabawne.
Kevin
55

DO#

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
źródło
4
Możesz użyć var htmli prawdopodobnie, var matchaby ogolić kilka postaci.
Superbest,
15
@Superbest Potrafię tworzyć nazwy jednoznakowe i htmlcałkowicie pozbywać się zmiennych, ale nie o to mi chodzi.
Athari,
6
@Najlepsze nie golfowy kod . : D
Kroltan
5
Cóż, poprawia również czytelność. Czy jest jakiś powód, aby nie używać, vargdy nie wpłynie to na semantykę kodu?
Superbest,
6
@ Superbest: „poprawia czytelność” jest subiektywny. Osobiście uważam, że wyraźne podanie typu zmiennej poprawia czytelność (zwykle jak w tym kodzie tutaj). Nie chcę jednak o tym dyskutować; Chcę tylko zaznaczyć, że istnieją alternatywne poglądy.
Cornstalks,
54

„Żadna strona trzecia” jest błędem

Uważam, że założenie „braku stron trzecich” jest błędem. Jest to szczególny błąd, który dotyka programistów C ++, ponieważ tak trudno jest stworzyć kod wielokrotnego użytku w C ++. Gdy w ogóle coś opracowujesz, nawet jeśli jest to mały skrypt, zawsze będziesz korzystać z wszelkich dostępnych fragmentów kodu wielokrotnego użytku.

Chodzi o to, że w językach takich jak Perl, Python, Ruby (by wymienić tylko kilka) ponowne użycie kodu innej osoby jest nie tylko łatwe, ale tak właśnie większość ludzi faktycznie pisze kod.

C ++, ze swoimi prawie niemożliwymi do utrzymania, kompatybilnymi wymaganiami ABI, sprawia, że ​​praca jest o wiele trudniejsza, kończy się projekt taki jak Boost, który jest monstrualnym repozytorium kodu i bardzo niewielką kompozycją poza nim.

Przykład CPAN

Dla zabawy, oto przykład oparty na CPAN, z poprawnym parsowaniem html, zamiast próby użycia wyrażenia regularnego do parsowania 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");
Daniel Ruoso
źródło
6
Głosuj za zajęciem się kwestią bibliotek stron trzecich, ale: cholera, zrobienie kodu wielokrotnego użytku w C ++ jest tak łatwe, jak w innym języku. Używanie, a zwłaszcza znajdowanie kodu wielokrotnego użytku może być nieco trudniejsze, ale jedyną poważną problematyczną kwestią jest ponowne użycie skompilowanych artefaktów, ale często nie jest to problem w interpretowanych językach takich jak Perl itp.
Martin Ba
4
Aby rozciągnąć analogię, Boost przypomina bardziej CPAN - wybierz i wybierz. Nie nazywasz CPAN „monstrualnym repozytorium kodu” tylko dlatego, że jest tam tak wiele rzeczy, których nie używasz?
Martin Ba
22
CPAN to „monstrualne repozytorium kodu”, według jakiejkolwiek rozsądnej definicji tych czterech słów.
jwg
3
@MartinBa Nie zgadzam się, ponieważ C ++ jest językiem kompilowanym, wymagającym od każdego pliku wykonywalnego przebudowania pełnego stosu zależności, ponieważ trudno jest utrzymać kompatybilność ABI poważnie utrudnia ponowne użycie kodu. Aby stworzyć bibliotekę wielokrotnego użytku w C ++, musisz przejść naprawdę długie odcinki, aby upewnić się, że nie zmuszasz się przez cały czas do zmian niezgodnych z ABI.
Daniel Ruoso
6
@MartinBa, ponieważ konieczność przebudowy całego wszechświata za każdym razem, gdy chcesz wdrożyć proste zadanie, jest nie do zniesienia.
Daniel Ruoso
47

Powłoka UNIX

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

Znajduje również ftp://link :)

Innym sposobem, bez polegania na ://składni:

lynx -dump -listonly http://www.stroustrup.com/C++.html | sed -n 's/^[ 0-9.]\+//p'
Ruslan
źródło
38
Nie mogę się zdecydować, czy dać +1, ponieważ użycie przeglądarki internetowej do pobrania strony internetowej jest właściwym narzędziem do zadania, czy -1, ponieważ wyzwaniem jest napisanie programu do zrobienia blahblahblah, a ty właśnie wywołałeś program do zrobienia buchanie.
David Richerby,
2
Myślę, że lepiej zastąpić rysia curl lub wget. Są one częściej używane do pobierania strony internetowej.
Pavel Strakhov
4
@PavelStrakhov Wybrałem rysia dokładnie dlatego, że może zrzucić linki beze mnie robienia czegoś specjalnego :)
Ruslan
2
@ SteveJessop przez „special” Mam na myśli parsowanie, wyrażenia regularne lub cokolwiek innego. W Lynxu po prostu przeglądam listę linków (których nie ma curl i wget) i usuwam numerację. Możesz myśleć o oszustwie lub czymkolwiek, ale pomyślałem, że fajnie jest {użyć narzędzia, które prawie idealnie robi to, co jest wymagane}, po prostu dostrajając efekt.
Ruslan
7
„ale biblioteki innych firm nie są dozwolone” . lynxW tym scenariuszu twierdzę, że jest funkcjonalnie równoważny bibliotece innej firmy.
Cyfrowy uraz
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;
}

Tego kodu można użyć jako stylu użytkownika do wyświetlania wyłącznie bezwzględnych linków na stronie na niesformatowanej liście. Może nie działać poprawnie, jeśli przeglądarka wymusza minimalny rozmiar czcionki.

Działa poprawnie z http://www.stroustrup.com/C++.html(uwaga !importantna background). Aby pracować na innych stronach z większą liczbą stylów, należy go rozszerzyć (zresetuj więcej właściwości, zaznacz właściwości jako ważne itp.).

Alternatywna wersja, która zawiera linki względne, z wyjątkiem linków intrapage zaczynających się od skrótów (opiera się niestety na bezwzględnym linku bezwzględnym)

* {
  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
źródło
16
To najgorsza rzecz, jaką kiedykolwiek widziałem. +1
Emmett R.
1
To jest piękne i całkowicie przerażające. +1
ricdesi
36

Clojure

(->> (slurp "http://www.stroustrup.com")
     (re-seq #"(?:http://)?www(?:[./#\+-]\w*)+"))
Adam
źródło
27
Slurp ?! Muszę się nauczyć Clojure.
11684
10
@ 11684 - Clojure posiada także standardowe funkcje nazwane spit, zipperi lazy-cat... :-)
Bob Jarvis
2
Wow, myślę, że to będzie późna noworoczna rezolucja. @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
źródło
2
Jestem trochę zawiedziony, biorąc pod uwagę, jak zwarty i niezwykle czytelny jest ten kod, że nie ma on więcej głosów. Dobra robota.
Spacemoose
28

Scala

"""\"(https?://.*?)\"""".r.findAllIn(scala.io.Source.fromURL("http://www.stroustrup.com/C++.html").mkString).foreach(println)
David Xu
źródło
8
spakuj wszystko w jednym wierszu - C ++ też może to zrobić
quetzalcoatl
Co ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler
22
@quetzalcoatl - To jest jedno wyrażenie , a nie tylko jedna linia. Możesz po prostu usunąć wszystkie podziały wiersza z kodu C ++, ale to nie to samo, co wykonanie całego zadania w jednym wyrażeniu.
DaoWen
4
@ RheoWen: Przepraszam, ale rozpoczęcie wyrażeń przeciw linii jest głupie. Dodaj funktory i C ++, możesz to zrobić. Ale to tylko pytanie o to, jakie biblioteki są uważane za „przyznane” i zawierają „zero kodu w środku”. Nie zmienia to faktu, że upakowanie go w linii powoduje utratę czytelności. Można go zatrzymać jako pojedyncze wyrażenie i po prostu sformatować go w kilku liniach, aby uzyskać dużo i stracić nic oprócz ... liczby linii. To mój punkt. Głupie pakowanie - C ++ też to potrafi. Jeśli ktoś chce wyjść z „głupiego opakowania”, powinien sformatować kod pod kątem czytelności, a nie numeru linii.
quetzalcoatl
3
@quetzalcoatl Tobias nie umieścił tam linku, abyśmy mogli go śledzić. Pytał autora tej odpowiedzi, dlaczego nie ma tego w jego wynikach.
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
źródło
5
Sugerowane zmiany: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(obecnie błąd); usuń array_unshift($m);(obecnie błąd, który prawdopodobnie miałeś na myśli array_shift); print_r($m);print_r($m[1]);( wysyłaj tylko adresy URL).
primo
naprawiono, dziękuję za wkład
David Xu,
@DavidXu Tyle że nie naprawiłeś tego ...?
Shahar
teraz jest naprawiony.!
David Xu,
25

PowerShell

Wyszukiwanie tekstowe wszystkich w pełni kwalifikowanych adresów URL (w tym JavaScript, CSS itp.):

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

Lub, aby uzyskać linki tylko w tagach zakotwiczonych (obejmuje względne adresy URL):

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

Krótsze wersje z komentarzy:

(iwr "http://www.stroustrup.com/C++.html").Links.href
(iwr "http://www.stroustrup.com/C++.html").Links.href-match":"
Justin Dunlap
źródło
6
Jeśli ktoś się zastanawia, iwrto alias Invoke-WebRequest(PS3 +).
Athari
8
Możesz nadużywać chęci PowerShell do spłaszczania kolekcji i robienia: (iwr "http://www.stroustrup.com/C++.html").Links.href(lub (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"tylko bezwzględnych URI)
Mathias R. Jessen
1
To całkiem przydatne!
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]); }
}
Kozzi11
źródło
Aby lista podobna do oryginalnej przykład, można rura wyjściowa programu poprzez | sort | uniqalbo zamiast dodać import std.arrayi zmienić linię .filter!("a")){ writeln(_.front[1]); }do tego: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Zauważ jednak, że wypróbowałem tylko ten kod i nie udowodniłem, że jest poprawny lub „idiomatyczny”. :)
Frg
22

Node.js

var http = require('http');

http.get('http://www.stroustrup.com/C++.html', function (res) {
    var data = '';
    res.on('data', function (d) {
        data += d;
    }).on('end', function () {
        console.log(data.match(/"https?:\/\/.*?"/g));
    }).setEncoding('utf8');
});
cPu1
źródło
3
Zastanawiam się, czy require('http').getdziała. Jeśli tak, możemy porzucić instrukcję var i skrócić kolejną linię.
Unihedron
@Unihedro Tak.
TimWolla,
9
@Unihedro Tak, ale to nie jest konkurs golfowy.
cPu1
Nie musisz używać żadnych grup przechwytywania.
Ry-
Myślę, że to JavaScript, a nie nazwa ramowa.
mr5
20

Rubin

require 'net/http'
result = Net::HTTP.get(URI.parse('http://www.stroustrup.com/C++.html'))
result.scan(/"((http)s?://.*?)"/)
Yahor Zylinski
źródło
1
Wyrażenie regularne zawiedzie, musisz użyć %r{"(https?://[^"]+)"}. Możesz także użyć, Net::HTTP.get('www.stroustrup.com', '/C++.html')aby skrócić żądanie (i zachować je do odczytu). Więc cały kod może być w jednej linii (utrzymując ją czytelny) puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Uruchom go, ruby -rnet/httpa nawet nie potrzebujesz require 'net/http'linii.
Hauleth,
20

Haskell

Niektóre problemy z "\w"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
źródło
Dlaczego typ jest resultwyraźnie określony? Powinno być w pełni ograniczone przez jego użycie w unlines.
John Dvorak,
1
To nieco rozciąga reguły, ponieważ nie ma ich Network.HTTPani TextRegex.Posixw basepakiecie. (Chociaż są na platformie Haskell i oczywiście na Hackage, więc ...)
przestali się obracać przeciwnie do zegara
1
@JanDvorak, zaczynam pisać w Ghci (prawdopodobnie powinienem to opublikować bez zmian). Ale twoja notatka jest ważna, dzięki.
vlastachu
@leftaroundabout, nie wiedziałem. Wygląda na to, że nie zrobiłbym tego, gdybym użył pakietu podstawowego.
vlastachu
networknie ma go baserównież, więc oszczędzaj na zwijanie własnych wiązań gniazd, nie ma praktycznego sposobu, aby to zrobić za pomocą just base.
Lambda Fairy,
18

PHP

O ile mi wiadomo, większość nowoczesnych instalacji PHP jest wyposażona w przetwarzanie DOM, więc oto ta, która faktycznie przegląda kotwice wewnątrz 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;
    }
}

Wewnętrzną pętlę można skrócić do:

preg_match('~^https?://~', $url = $a->getAttribute('href')) && printf("%s\n", $url);
Jacek
źródło
Właściwie chciałem to wymyślić (jako moją pierwszą odpowiedź tutaj). Zrobiłeś to pierwszy, więc oto twoja +1 (za nieużywanie podatnego na błędy Regex)! Podpowiedź: Można użyć lame 1zamiast truedo in_arrayścisłego wyszukiwania. Możesz również pominąć nawiasy kwadratowe. Nie jestem do końca pewien, ale równie dobrze możesz upuścić httpi tylko zostawić ://(idź bez schematu). .
kaiser
I: Inną możliwością byłoby odrzucenie na if ( ) {}korzyść in_array() and print $url.PHP_EOL. Ale tak, dostałbyś kolejne +1 (gdybym mógł) za najlepszą czytelność :)
kaiser
Właśnie wypróbowałem swój przykład i dostałem błąd dotyczący ścisłych standardów (PHP 5.4). Wygląda na to, że w źródle jest gdzieś uszkodzony lub źle sformatowany link z brakującym średnikiem. Możesz wyłączyć raportowanie błędów za pomocą @\DOMDocument. Właśnie to wypróbowałem i mogę potwierdzić, że działa.
kaiser
Nie, to błędna dokumentacja; technicznie nie powinieneś dzwonić ::loadHTMLFile()statycznie, a dodanie @tylko ukrywa ten artefakt.
Jack
2
To zdecydowanie jedno z najbardziej „poprawnych” rozwiązań, jedno z niewielu, jakie widziałem w produkcji. dobra robota
Jordon Biondo,
14

Powłoka Unix

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

Chociaż muszę przyznać, że to nie działa, jeśli w linii jest więcej niż jeden link.

Guntram Blohm
źródło
1
curl http://www.stroustrup.com/C++.htmlzapisuje kilka znaków.
l0b0
7
„ale biblioteki innych firm nie są dozwolone” . Myślę, że skoro wgetjest GNU (podobnie jak bash), można argumentować, że nie jest to firma zewnętrzna. Ale curlzdecydowanie jest to firma zewnętrzna.
Cyfrowy uraz
Co ftp://ftp.research.att.com/pub/c++std/WP/CD2i https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler
4
@TobiasKienzler Wydaje mi się, że oryginalny kod Stroustrupa też ich nie znajduje
Ruslan
14

Jawa

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
źródło
3
Czy potrafisz poprawnie sformatować kod w swoich odpowiedziach? To nie jest konkurencja dla najmniej czytelnego kodu. Możesz go sformatować, aby uniknąć przynajmniej poziomych pasków przewijania.
Athari
Jeśli używasz Scanner, możesz zmusić go do przetwarzania wzorca wyrażeń regularnych dla linków bezpośrednio i iteracji Scannerwyników.
Holger
5
Tak ... to jest dla ciebie Java. Używanie go do golfa kodowego to odważne przedsięwzięcie.
javadba
4
Nigdy nie myślałem, że zobaczę rozwiązanie Java, które faktycznie jest krótsze niż C ++!
slebetman
2
Korekta do mojego ostatniego komentarza: muszę przyznać, że jest to najkrótszy i najczystszy kod, jaki można napisać w Javie. Wypróbowałem podejście parsera SAX, które może być jeszcze krótsze przy użyciu lambdas, ale strona internetowa nie jest XHTML, a parser zgłasza wyjątki. Regex to jedyna droga.
Mister Smith,
11

Groovy

"http://www.stroustrup.com/C++.html".toURL().text.findAll(/https?:\/\/[^"]+/).each{println it}
cfrick
źródło
Można to poprawić za pomocą? operator, aby uniknąć NPE?
Chris K
2
@ChrisKamiński i być pierwszym (obok Bjarne) tutaj, aby sprawdzić błędy? nigdy! poza tym: widzę tu tylko wyjątki związane z IO. gdzie widzisz NPE?
Por.
findAll () może zwrócić null, nie? Czy zwróci pustą listę? Nadal trochę nowy w Groovy. EDYCJA: nm, wygląda jak findAll () zwraca pustą listę. Ci Groovy byli tacy sprytni. :-)
Chris K
11

SQL (SQL Anywhere 16)

Zdefiniuj procedurę przechowywaną, aby pobrać stronę internetową

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

Utwórz zestaw wyników za pomocą jednego zapytania

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;

Ograniczenia: Daje to do 256 linków. Jeśli istnieje więcej linków, zwiększ 256 do odpowiedniej wartości.

Jack w SAP Canada
źródło
2
Nie wierzyłem, że golf będzie w SQL ... aż do teraz.
vaxquis
Rozumiem ... „linki”. :-)
Jack w 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
źródło
1
Myślę, że to jest CoffeeScript / Node? Myślę, że powinieneś sprecyzować, że ...
John Dvorak
Łał. To bardzo czytelne.
slebetman
@slebetman jest zdecydowanie niewielki
John Dvorak
@slebetman Yeah CoffeeScript jest o wiele bardziej czytelny niż JavaScript :) Cieszyłem się, że pozbyłem się wszystkich nawiasów klamrowych} :)
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
źródło
1
Kod byłby bardziej przejrzysty, gdybyś uniknął zmiennych separatora pól i separatorów rekordów i po prostu zrobił: wydrukuj mapę {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso,
@DanielRuoso zgodził się.
primo
a nawet use v5.10;i say for $response->content...
Mark Reed
Przypuszczam, że każdemu z nich. Niektóre z backportowanych funkcji perl6 były problematyczne (inteligentne dopasowanie, patrzę na ciebie), ale saysą całkiem przydatne i moim zdaniem tutaj bardziej zrozumiałe. (Ponadto w ciągu ostatnich 13 lat wprowadzono wiele całkowicie niezwiązanych z perl6izmem ulepszeń w perl5; może warto sprawdzić).
Mark Reed
@ MarkReed Zgadzam się, że sayprawdopodobnie jest to bardziej czytelne w tym przypadku, szczególnie dla osób mniej zaznajomionych z perlem.
primo,
9

R

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

... chociaż R jest napisany głównie w C ... więc prawdopodobnie kilka linii kodu C za tymi 2 liniami kodu R.

Rusan Kax
źródło
2
To (lub coś podobnego) jest prawdziwe dla prawie wszystkich odpowiedzi tutaj.
JLRishe
8

Cel 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
źródło
3
Co? Proszę napisać wersję Swift. Ten nonsens z nawiasami kwadratowymi rani mnie w oczy :)
Mister Smith,
2
Hurra dla []! Powinniśmy również całkowicie dodać wersję Smalltalk;)
Bersaelor,
@MisterSmith Swift odpowiedź jest teraz dostępna tutaj .
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.
źródło
Możesz uciec, robiąc http :: data w puts. Nie ma potrzeby tworzenia zmiennej tymczasowej. Sformatowałbym to również, wprowadzając nowe wiersze i wcięcia [. Ale to wybór stylu.
slebetman
7

Iść

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 ten kod odczytuje całe źródło do pamięci, więc rozważ użycie regexp.FindReaderIndexwyszukiwania w strumieniu, dzięki czemu aplikacja będzie kuloodporna.

Maxim Kupriianov
źródło
6

CJam

CJam nie ma wyrażenia regularnego, więc w tym przypadku musiałem zastosować inne podejście:

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

Najpierw konwertuję wszystko 'na ", następnie dzielę na wszystkie ", biorę każdy alternatywny ciąg, a następnie filtruję tę listę pod kątem ciągów rozpoczynających się od http://lubhttps:// . Następnie po prostu wydrukuj każdy filtrowany ciąg w nowej linii.

Spróbuj, używając interpretera Java, takiego jak

java -jar cjam-0.6.2.jar file.cjam

gdzie plik.cjam ma treść powyższego kodu.

Optymalizator
źródło
9
Nie wiem o części czytelnej ... nie wiedziałem, że Cjam ma funkcjonalność internetową
Def
Jeśli chcesz zagrać w golfa ... ''/'"f/:+dla ''/'"*'"/'"f/0f=.
jimmy23013
... czekaj, dlaczego '"f/0f=tam jest ? Czy to ma coś zrobić ( 2%na przykład)?
jimmy23013
6

FA#

Ten kod może być znacznie krótszy, ale napisałbym coś takiego, gdybym kiedykolwiek spodziewał się, że będę musiał go przeczytać lub użyć ponownie, aby zawierał wiele niepotrzebnych adnotacji typu. Pokazuje użycie aktywnego wzorca MatchValue, aby umożliwić dopasowanie wzorca do standardowego dopasowania typu CLR

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)

Edycja Zrobiłem getLinks własną funkcję

SourceSimian
źródło
Bardzo podoba mi się sposób, w jaki używałeś adnotacji. Myślę, że nazewnictwo wartości opisujących to, co zwracasz, jest w porządku, ale nazwa funkcji jest wystarczająco wyrazista: wartość getHTML i html, wartość getLinks i wartość linków. Ostatnie dwa wiersze mogą być linkami |> Seq.iter (printfn "% s")
MichalMa
@MichalMa Zgadzam się, że nazwa funkcji sama w sobie jest wystarczająco ekspresyjna, zmienne HTML i Link są tam z powodów pragmatycznych: więc jest gdzieś, aby ustawić punkt przerwania. Użyłem pętli for zamiast List.iter tylko dlatego, że podoba mi się sposób, w jaki czyta więcej, chociaż w replice prawdopodobnie użyłbym List.iter.
SourceSimian