Debunking Stroustrup menyangkal mitos “C ++ hanya untuk program yang besar, rumit,”


161

Stroustrup baru-baru ini memposting serangkaian postingan yang menghilangkan mitos populer tentang C ++ . Mitos kelima adalah: "C ++ hanya untuk program yang besar, rumit,". Untuk menghilangkan prasangka itu, ia menulis sebuah program C ++ sederhana yang mengunduh halaman web dan mengekstraksi tautan darinya . Ini dia:

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

Mari kita tunjukkan pada Stroustrup apa program kecil dan mudah dibaca itu sebenarnya.

  1. Unduh http://www.stroustrup.com/C++.html
  2. Daftar semua tautan:

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

Anda dapat menggunakan bahasa apa pun, tetapi tidak ada perpustakaan pihak ketiga yang diizinkan.

Pemenang

Jawaban C ++ dimenangkan oleh suara, tetapi bergantung pada pustaka pihak ketiga (yang tidak diizinkan oleh aturan), dan, bersama dengan pesaing dekat lainnya Bash , bergantung pada klien HTTP yang diretas bersama (tidak akan bekerja dengan HTTPS, gzip, arahan ulang dll). Jadi Wolfram adalah pemenang yang jelas. Solusi lain yang mendekati dalam hal ukuran dan keterbacaan adalah PowerShell (dengan peningkatan dari komentar), tetapi belum mendapat banyak perhatian. Bahasa arus utama ( Python , C # ) juga cukup dekat.


43
Untuk masing-masing miliknya, aku dipanggil lebih buruk. Jika tujuan OP bukan untuk mencoba dan entah bagaimana membuktikan bahwa Stroustrup salah, maka saya akan setuju dengan penilaian Anda. Tetapi keseluruhan premis dari pertanyaan ini adalah untuk menunjukkan bagaimana "bahasa favorit Anda" dapat melakukan hal yang sama dengan 50 baris C ++ ini di baris kode yang jauh lebih sedikit. Masalahnya adalah tidak ada contoh yang melakukan hal yang sama. Secara khusus, tidak ada jawaban yang melakukan pengecekan kesalahan, tidak ada jawaban yang menyediakan fungsi yang dapat digunakan kembali, sebagian besar jawaban tidak menyediakan program lengkap. Contoh Stroustrup memberikan semua itu.
Dunk

19
Yang menyedihkan adalah halaman webnya bahkan tidak valid UTF-8 . Sekarang saya harus mengatasinya, terlepas dari iklan servernya Content-Type: text/html; charset=UTF-8... Saya akan mengirim email kepadanya.
Cornstalks

27
@Dunk Contoh-contoh lain tidak menyediakan fungsi yang dapat digunakan kembali karena mereka menyelesaikan seluruh fungsionalitas fungsi-fungsi itu dalam satu baris dan tidak masuk akal untuk membuat keseluruhan fungsi itu sendiri, dan contoh C ++ tidak melakukan pengecekan kesalahan yang tidak ditangani secara asli dalam cara yang hampir identik, dan frasa "program lengkap" hampir tidak ada artinya.
Jason

16
"Anda dapat menggunakan bahasa apa pun, tetapi tidak ada perpustakaan pihak ketiga yang diizinkan." Saya tidak berpikir itu persyaratan yang adil mengingat boost/asiodigunakan di sana yang merupakan perpustakaan pihak ketiga. Maksud saya, bagaimana bahasa yang tidak menyertakan url / tcp fetching sebagai bagian dari perpustakaan standarnya akan bersaing?
Greatwolf

Jawaban:


116

Wolfram

Ini terasa seperti selingkuh total

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

Jadi, tambahkan saja penguraian jujur ​​di atas

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

49
Tidak, saya tidak melihat ada kecurangan di sini. Tantangan ini adalah tentang mengeluarkan yang terbaik dari bahasa Anda. Dan baris pertama itu adalah lambang "kecil dan mudah dibaca".
Martin Ender

Sebuah jawaban yang dapat mengabaikan argumen konyol tentang menangkap tautan ftp. Cemerlang.
Seth Battin

Datang ke sini untuk menawarkan solusi tepat ini, senang melihat orang lain juga menghargainya.
Michael Stern

@ MartinBüttner Dalam hal ini Anda mungkin ingin mempertimbangkan downvoting meta.codegolf.stackexchange.com/a/1078/12130
David Mulder

6
@ Davidvidulder Secara teknis, celah saat ini tidak valid, karena rincian suara adalah + 41 / -21 (dan pertanyaan celah menyatakan bahwa celah diterima jika ada setidaknya dua kali lebih banyak upvote daripada downvotes). Panggilan dekat, memang, tapi tetap saja. ;) Selain itu, ini adalah kontes popularitas, bukan golf kode, dan khususnya, ini adalah pop-con tentang menunjukkan betapa mudahnya ini dapat dilakukan dalam bahasa tertentu, itulah sebabnya saya pikir celah itu tidak benar-benar berlaku untuk bagaimanapun juga tantangan ini (karena tantangan pada dasarnya memintanya).
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";
}

Kelemahan utama adalah sifat canggung boost :: asio, saya yakin bisa lebih pendek dengan perpustakaan yang lebih baik.


166
Lucu bagaimana "tidak ada perpustakaan pihak ketiga" berarti Python mungkin masih import urllib2, C3 mungkin masih using System.Net, Haskel mungkin masih import Network.HTTP, tetapi seorang pembuat kode C ++ harus membuat alasan #include <boost/asio.hpp>seolah-olah memiliki metrik crapton dari perpustakaan khusus C ++ (dan C!) Yang dibuat khusus tersedia untuk dipilih adalah sesuatu yang memalukan hanya karena panitia tidak repot-repot memberi Anda makan satu ...
DevSolar

19
@DevSolar hampir berhasil membuat akun kedua untuk memberi Anda upvote lain untuk komentar itu
pengguna

15
@DevSolar System.Nettidak dipaksakan, itu hanya perpustakaan berkualitas tinggi yang mengikuti semua. Rekomendasi NET yang disertakan dengan bahasa. Sudah ada implementasi alternatif, tetapi memiliki dukungan HTTP di perpustakaan standar berarti menulis aplikasi sederhana adalah sederhana, berarti interoperabilitas yang lebih baik antara perpustakaan pihak ketiga, berarti lebih sedikit ketergantungan, berarti implementasi yang mudah untuk fasad dll. Bayangkan dunia tanpa std::string, bayangkan bagaimana semua orang menggunakan perpustakaan mereka sendiri, bayangkan semua kesulitan yang menyertainya.
Athari

17
@DevSolar: urllib2adalah tidak pihak ke-3. Ini di stdlib seperti <iostream>di C ++. urllib2di Python selalu tersedia tidak seperti <boost/asio.hpp>di C ++. Jika kami diizinkan menggunakan modul pihak ke-3; Saya akan menggunakan lxmlatau BeautifulSoupdengan Python.
jfs

22
Juga, saya pikir komentar paling penting di sini adalah hanya bahwa C ++ tidak menstandarisasi banyak hal dalam pustaka standar seperti bahasa lain, tetapi masih ada banyak pustaka portabel yang kuat dan banyak digunakan untuk banyak tugas yang sama yang merupakan standar dalam bahasa seperti python, dan beberapa lib ini hampir merupakan standar de-facto. Dan beberapa di antaranya adalah hasil dari C ++ yang dapat menargetkan sistem tertanam dengan binari kecil dan perpustakaan kecil.
Peter Cordes

85

Pure Bash di Linux / OS X (tidak ada utilitas eksternal)

Perangkat lunak klien HTTP terkenal membengkak. Kami tidak menginginkan ketergantungan seperti itu. Sebagai gantinya, kami dapat menekan tajuk yang sesuai ke aliran TCP dan membaca hasilnya. Tidak perlu memanggil utilitas kuno seperti grep atau sed untuk menguraikan hasilnya.

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 - Saya kira itu bisa lebih mudah dibaca ...


1
Seperti ini menggunakan pegangan file unix untuk pipa.
javadba

2
Wow, tidak pernah terpikir orang bisa melakukan ini tanpa utilitas eksternal. Meskipun tampaknya bash 3.2.17 saya di LFS sedikit usang sehingga tidak mendukung mapfile:)
Ruslan

@Ruslan Yep, mapfilehadir dengan bash 4.x. Hal yang sama juga bisa dilakukan dengan while readloop.
Trauma Digital

3
@Ruslan saya mengubahnya menjadi while readbukan mapfile. Lebih portabel dan lebih mudah dibaca, saya pikir.
Digital Trauma

1
Bekerja pada OS X, juga!
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

Lumpuh, tapi berhasil


9
Mengapa tidak membuat banyak panggilan itu? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Nama Palsu

13
Ini pendek tetapi tidak idiomatik (keterbacaan diperhitungkan dalam Python)
jfs

24
Hmmm ... jika semua kode saya mengabaikan kesalahan seperti contoh ini maka 75% hingga 90% pekerjaan saya sudah dilakukan pada setiap proyek yang saya kerjakan.
Dunk

20
@Dunk: Misalkan contohnya memang menangkap beberapa pengecualian (misalnya dari urlopen()). Apa yang harus dilakukan dengan pengecualian seperti itu, selain crash dan mati? Jika itu akan crash dan mati, mengapa tidak membiarkan Python yang menangani crash-dan-sekarat, dan meninggalkan penanganan pengecualian sama sekali?
Kevin

8
@Dunk: Jika saya menggunakan kode Python orang lain, saya lebih suka mereka tidak menangkap urlopenkesalahan daripada (katakanlah) menangkap mereka dan menelepon sys.exit("something's borked!"). Jika mereka melakukan yang terakhir, saya harus menangkap SystemExit, yang tidak pernah menyenangkan.
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
Anda dapat menggunakan var html, dan mungkin var matchuntuk memangkas beberapa karakter.
Hebat

15
@Superbest Saya bisa membuat nama karakter tunggal dan menyingkirkan htmlvariabel sama sekali, tapi bukan itu yang saya cari.
Athari

6
@Superbest bukan kode-golf . : D
Kroltan

5
Yah, itu meningkatkan keterbacaan juga. Apakah ada alasan untuk tidak menggunakannya varketika tidak akan memengaruhi kode semantik?
Hebat,

6
@Superbest: "itu meningkatkan keterbacaan" adalah subyektif. Secara pribadi, saya pikir secara eksplisit menyatakan jenis variabel meningkatkan keterbacaan (biasanya, seperti dalam kode ini di sini). Saya tidak ingin memperdebatkan ini; Saya hanya ingin menunjukkan bahwa ada pandangan alternatif.
Cornstalks

54

"Tidak ada pihak ketiga" adalah kekeliruan

Saya pikir asumsi "tidak ada pihak ketiga" adalah kesalahan. Dan merupakan kesalahan spesifik yang menimpa pengembang C ++, karena sangat sulit untuk membuat kode yang dapat digunakan kembali dalam C ++. Ketika Anda sedang mengembangkan apa pun, bahkan jika itu adalah skrip kecil, Anda akan selalu memanfaatkan potongan kode apa pun yang dapat digunakan kembali yang tersedia untuk Anda.

Masalahnya adalah, dalam bahasa seperti Perl, Python, Ruby (untuk beberapa nama), menggunakan kembali kode orang lain tidak hanya mudah, tetapi itu adalah bagaimana kebanyakan orang benar-benar menulis kode sebagian besar waktu.

C ++, dengan hampir tidak mungkin untuk mempertahankan yang kompatibel-ABI-persyaratan membuat pekerjaan yang lebih sulit, Anda berakhir dengan proyek seperti Boost, yang merupakan repositori kode yang mengerikan dan sangat sedikit kompabilitas di luarnya.

Contoh CPAN

Hanya untuk bersenang-senang, ini contoh berbasis CPAN, dengan penguraian html yang tepat, alih-alih mencoba menggunakan regex untuk mengurai 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
Suara positif untuk mengatasi titik lib pihak ke-3, tetapi: omong kosong, membuat kode yang dapat digunakan kembali dalam bahasa C ++ sama mudahnya dengan bahasa lainnya. Menggunakan dan terutama menemukan kode yang dapat digunakan kembali mungkin sedikit lebih sulit, tetapi satu-satunya hal yang sangat bermasalah adalah menggunakan kembali artefak yang dikompilasi , tetapi itu sering kali bukan masalah dalam bahasa yang ditafsirkan seperti Perl, dll.
Martin Ba

4
Untuk merentang analogi, Boost lebih seperti CPAN - pilih dan pilih. Anda tidak menyebut CPAN "repositori kode yang mengerikan" hanya karena ada banyak hal di sana yang tidak Anda gunakan?
Martin Ba

22
CPAN adalah 'repositori kode yang mengerikan', dengan definisi yang masuk akal dari keempat kata tersebut.
jwg

3
@MartinBa Saya tidak setuju, C ++ menjadi bahasa yang dikompilasi, mengharuskan setiap yang dapat dieksekusi untuk membangun kembali setumpuk dependensinya karena sulit untuk mempertahankan kompatibilitas ABI yang secara serius menghambat penggunaan kembali kode. Untuk menghasilkan pustaka yang dapat digunakan kembali dalam C ++, Anda harus melewati waktu yang sangat panjang untuk memastikan Anda tidak memaksakan diri Anda pada perubahan yang tidak kompatibel ABI sepanjang waktu.
Daniel Ruoso

6
@MartinBa karena harus membangun kembali seluruh alam semesta setiap kali Anda ingin mengimplementasikan tugas sederhana tidak tertahankan.
Daniel Ruoso

47

UNIX shell

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

Juga menemukan ftp://tautan :)

Cara lain, tanpa mengandalkan ://sintaks:

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

38
Saya tidak dapat menentukan apakah akan memberi +1 karena menggunakan peramban web untuk mengunduh laman web adalah alat yang tepat untuk pekerjaan itu atau ke -1 karena tantangannya adalah menulis program untuk melakukan blahblahblah dan Anda baru saja memanggil program untuk melakukan blahing itu.
David Richerby

2
Saya pikir lebih baik mengganti lynx dengan curl atau wget. Mereka lebih umum digunakan untuk mengunduh halaman web.
Pavel Strakhov

4
@PavelStrakhov Saya memilih lynx karena ia dapat membuang tautan tanpa saya melakukan sesuatu yang istimewa :)
Ruslan

2
@SteveJessop dengan "spesial" Maksudku sebenarnya parsing atau regexing atau apa pun. Dengan lynx saya hanya mengeluarkan daftar tautan (yang curl dan wget tidak mencantumkan) dan menghapus penomorannya. Anda mungkin menganggapnya curang atau apa pun, tapi saya pikir itu menyenangkan untuk {menggunakan alat yang hampir sempurna melakukan apa yang diperlukan}, hanya menyempurnakan output.
Ruslan

7
"tetapi tidak ada perpustakaan pihak ketiga yang diizinkan" . Saya berpendapat bahwa lynxsecara fungsional setara dengan perpustakaan pihak ketiga dalam skenario ini.
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;
}

Kode ini dapat digunakan sebagai gaya pengguna untuk hanya menampilkan tautan absolut pada halaman dalam daftar yang tidak diformat. Ini mungkin tidak berfungsi dengan benar jika browser Anda memberlakukan ukuran font minimum.

Ini berfungsi dengan baik http://www.stroustrup.com/C++.html(catatan !importantaktif background). Agar dapat bekerja di halaman lain dengan gaya yang lebih banyak, itu harus diperluas (reset lebih banyak properti, tandai properti sebagai penting, dll.).

Versi alternatif yang mencakup tautan relatif kecuali tautan intrapage dimulai dengan hash (sayangnya, ini bergantung pada tautan absolut yang dikodekan dengan keras):

* {
  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
Ini adalah hal terburuk yang pernah saya lihat. +1
Emmett R.

1
Ini indah dan benar-benar mengerikan. +1
ricdesi

36

Clojure

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

28
Mencucup?! Saya perlu belajar Clojure.
11684

10
@ 11.684 - Clojure juga memiliki fungsi standar bernama spit, zipperdan lazy-cat... :-)
Bob Jarvis

2
Wow, saya pikir itu akan menjadi Resolusi Tahun Baru yang terlambat. @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
Saya sedikit kecewa, mengingat betapa kompak dan mudah dibaca kode ini, bahwa tidak memiliki lebih banyak suara. Sudah selesai dilakukan dengan baik.
Spacemoose

28

Scala

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

8
kemas semuanya dalam satu baris - C ++ dapat melakukannya juga
quetzalcoatl

Bagaimana dengan ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl - Ini adalah satu ekspresi , bukan hanya satu baris. Anda bisa menghapus semua jeda baris dari kode C ++, tapi itu tidak sama dengan melakukan seluruh tugas dalam satu ekspresi.
DaoWen

4
@PORWen: Maaf, tetapi memulai ekspresi-vs-line hanya akan konyol. Tambahkan beberapa functors dan C ++ Anda dapat melakukannya juga. Tapi itu hanya pertanyaan tentang apa lib dianggap dianggap "diberikan" dan memiliki "kode nol di dalam". Itu tidak mengubah fakta bahwa mengemasnya menjadi satu baris akan mudah dibaca. Satu dapat menyimpannya tetap sebagai satu ekspresi dan hanya memformatnya menjadi beberapa baris untuk mendapatkan banyak dan kehilangan apa pun selain .. jumlah baris. Itu maksudku. Pengepakan konyol - C ++ dapat melakukannya juga. Jika seseorang ingin keluar dari kotak "kemasan konyol", maka harus memformat kode untuk dibaca, bukan linecount.
quetzalcoatl

3
@quetzalcoatl Tobias tidak menaruh tautan di sana agar kami mengikutinya. Dia bertanya kepada penulis jawaban ini mengapa itu tidak ada dalam hasilnya.
JLRishe

25

PHP 5

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

5
Pengeditan yang disarankan: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(saat ini merupakan kesalahan); hapus array_unshift($m);(saat ini merupakan kesalahan, yang mungkin Anda maksudkan adalah array_shift); print_r($m);print_r($m[1]);(hanya menampilkan url).
Primo

diperbaiki, terima kasih atas masukan Anda
David Xu

@ DavidXu Kecuali Anda tidak memperbaikinya ...?
Shahar

sekarang sudah diperbaiki.!
David Xu

25

PowerShell

Pencarian teks untuk semua URL yang sepenuhnya memenuhi syarat (termasuk JavaScript, CSS, dll.):

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

Atau untuk mendapatkan tautan di tag jangkar saja (termasuk URL relatif):

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

Versi lebih pendek dari komentar:

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

6
Jika ada yang bertanya-tanya, iwradalah alias untuk Invoke-WebRequest(PS3 +).
Athari

8
Anda dapat menyalahgunakan keinginan PowerShell untuk meratakan koleksi dan melakukan: (iwr "http://www.stroustrup.com/C++.html").Links.href(atau (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"hanya untuk URI absolut)
Mathias R. Jessen

1
Itu sangat berguna!
Justin Dunlap

22

D

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

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

Untuk membuat daftar serupa dengan contoh asli, Anda bisa pipa output program melalui | sort | uniqatau sebaliknya menambah import std.arraydan mengubah baris .filter!("a")){ writeln(_.front[1]); }ke ini: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Namun, perhatikan bahwa saya hanya mencoba kode ini dan tidak membuktikannya benar atau "idiomatik". :)
Frg

22

Node.js

var http = require('http');

http.get('http://www.stroustrup.com/C++.html', function (res) {
    var data = '';
    res.on('data', function (d) {
        data += d;
    }).on('end', function () {
        console.log(data.match(/"https?:\/\/.*?"/g));
    }).setEncoding('utf8');
});

3
Saya ingin tahu apakah itu require('http').getberhasil. Jika ya maka kita bisa menghilangkan pernyataan var dan mempersingkat baris lain.
Unihedron

@ Unihedro Ya.
TimWolla

9
@ Unihedro Ya, tapi ini bukan kontes golf.
cPu1

Anda tidak perlu menggunakan grup penangkap apa pun.
Ry-

Saya pikir itu JavaScript daripada nama kerangka kerja.
mr5

20

Rubi

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

1
Regex Anda akan gagal, Anda perlu menggunakannya %r{"(https?://[^"]+)"}. Anda juga dapat menggunakan Net::HTTP.get('www.stroustrup.com', '/C++.html')untuk mempersingkat permintaan (dan membuatnya mudah dibaca). Jadi seluruh kode bisa dalam satu baris (menjaga dibaca): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Jalankan dengan ruby -rnet/httpdan Anda bahkan tidak perlu require 'net/http'garis.
Hauleth

20

Haskell

Beberapa masalah dengan "\w"di 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

Mengapa jenis yang resultditentukan secara eksplisit? Itu harus sepenuhnya dibatasi oleh penggunaannya di unlines.
John Dvorak

1
Hal ini meregangkan aturan sedikit, mengingat tidak Network.HTTPjuga TextRegex.Posixberada di basepaket. (Meskipun mereka berada di Platform Haskell, dan tentu saja di Hackage, jadi ...)
berhenti mengubah counterclockwis

1
@ JanDvorak, saya mulai menulis dalam ghci (mungkin saya harus mempostingnya tidak berubah). Tetapi catatan Anda relevan, terima kasih.
vlastachu

@ Leftaroundabout, tidak tahu. Sepertinya saya tidak bisa melakukannya, jika menggunakan paket dasar.
vlastachu

networktidak ada di basekeduanya, jadi simpan untuk menggulung binding socket Anda sendiri tidak ada cara praktis untuk melakukannya hanya dengan base.
Lambda Fairy

18

PHP

Sejauh yang saya tahu, sebagian besar instalasi PHP modern datang dengan pemrosesan DOM, jadi inilah salah satu yang sebenarnya melintasi jangkar di dalam 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;
    }
}

Lingkaran dalam dapat disingkat menjadi:

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

Sebenarnya ingin muncul dengan ini (sebagai jawaban pertama saya di sini). Anda melakukannya terlebih dahulu, jadi inilah +1 Anda (karena tidak menggunakan Regex yang rentan kesalahan)! Petunjuk: Anda bisa menggunakan timpang 1alih-alih trueuntuk in_arraypencarian ketat. Anda juga bisa menghilangkan tanda kurung. Saya tidak sepenuhnya yakin, tetapi jika Anda bisa juga drop httpdan hanya meninggalkan ://(pergi w / o skema). .
kaiser

Dan: Kemungkinan lain adalah menjatuhkan if ( ) {}dukungan in_array() and print $url.PHP_EOL. Tapi ya, Anda akan mendapatkan +1 lagi (jika saya bisa) untuk keterbacaan terbaik :)
kaiser

Coba saja contoh Anda dan dapatkan kesalahan untuk standar ketat (PHP 5.4). Sepertinya di sumbernya, ada tautan yang rusak atau salah diformat dengan titik koma yang hilang. Anda dapat mematikan pelaporan kesalahan dengan menggunakan @\DOMDocument. Baru saja mencobanya dan dapat mengonfirmasi itu berfungsi.
kaiser

Nah, itu dokumentasi yang salah; secara teknis Anda tidak seharusnya menelepon ::loadHTMLFile()secara statis, dan menambahkan @hanya menyembunyikan artefak itu.
Jack

2
Ini jelas merupakan salah satu solusi yang paling "benar", satu-satunya solusi yang dapat saya lihat saat digunakan dalam produksi. pekerjaan yang bagus
Jordon Biondo

14

Unix Shell

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

Meskipun saya harus mengakui ini tidak berfungsi jika ada lebih dari satu tautan pada satu baris.


1
curl http://www.stroustrup.com/C++.htmlmenyimpan beberapa karakter.
l0b0

7
"tetapi tidak ada perpustakaan pihak ketiga yang diizinkan" . Saya kira karena wgetitu GNU (seperti halnya bash), Anda bisa berargumen bahwa itu bukan pihak ketiga. Tapi yang curlpasti pihak ketiga.
Digital Trauma

Bagaimana dengan ftp://ftp.research.att.com/pub/c++std/WP/CD2dan https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

4
@TobiasKienzler Saya kira kode asli Stroustrup juga tidak menemukan mereka
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());
    }
}

3
Bisakah Anda memformat kode dengan benar dalam jawaban Anda? Itu bukan kompetisi untuk kode yang paling tidak mudah dibaca. Anda dapat memformatnya untuk menghindari setidaknya scrollbar horizontal.
Athari

Jika Anda menggunakan, ScannerAnda dapat membuatnya memproses pola regex untuk tautan secara langsung dan beralih pada Scannerhasil.
Holger

5
Yap .. itu java untuk Anda. Menggunakannya untuk kode golf adalah usaha yang berani.
javadba

4
Tidak pernah terpikir saya akan melihat solusi java yang sebenarnya lebih pendek dari C ++!
Pelari

2
Koreksi komentar terakhir saya: Saya harus akui ini adalah kode terpendek dan terbersih yang dapat ditulis di Jawa. Saya sudah mencoba pendekatan parser SAX, yang bisa dibuat lebih pendek dengan lambdas, tetapi halaman web bukan XHTML dan parser melempar pengecualian. Regex adalah satu-satunya cara untuk maju.
Tuan Smith

11

Asyik

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

Dapat ditingkatkan dengan menggunakan? operator untuk menghindari NPE?
Chris K

2
@ChrisKaminski dan jadilah yang pertama (di samping Bjarne) di sini untuk memeriksa kesalahan? tidak pernah! di samping itu: saya hanya melihat pengecualian terkait IO di sini. di mana Anda melihat NPE?
cfrick

findAll () dapat mengembalikan nol, bukan? Atau akankah mengembalikan daftar kosong? Masih agak baru bagi Groovy. EDIT: nm, sepertinya findAll () mengembalikan daftar kosong. Orang-orang asyik itu sangat pintar. :-)
Chris K

11

SQL (SQL Anywhere 16)

Tetapkan prosedur tersimpan untuk mengambil halaman web

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

Menghasilkan set hasil menggunakan satu permintaan

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;

Keterbatasan: Ini menghasilkan hingga 256 tautan. Jika ada lebih banyak tautan, maka tambah 256 ke nilai yang sesuai.


2
Saya tidak percaya akan ada golf di SQL ... sampai sekarang.
vaxquis

Saya mengerti ... "tautan". :-)
Jack at SAP Canada

10

CoffeeScript / NodeJS

require('http').get 'http://www.stroustrup.com/C++.html', (r) ->
    dt = '';
    r.on 'data', (d) -> dt += d
    r.on 'end' , (d) -> console.log dt.match /"((http)s?:\/\/.*?)"/g

1
Saya kira ini CoffeeScript / Node? Saya kira Anda harus menentukan itu ...
John Dvorak

Wow. Itu sangat mudah dibaca.
Slebetman

@slebetman itu pasti kecil
John Dvorak

@slebetman Ya CoffeeScript jauh lebih mudah dibaca daripada JavaScript :) Saya senang bisa menyingkirkan semua kurung kurawal} :)
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
Kode akan lebih jelas jika Anda menghindari variabel pemisah-bidang dan pemisah-catatan dan baru saja melakukannya: cetak peta {"$ _ \ n"} $ response-> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso

@DanielRuoso setuju.
primo

atau bahkan use v5.10;dan say for $response->content...
Mark Reed

Untuk masing-masing miliknya, kurasa. Beberapa fitur perl6 yang di-backport telah bermasalah (pencocokan pintar, saya melihat Anda), tetapi saycukup berguna, dan dalam benak saya lebih jelas di sini. (Juga, ada banyak perbaikan perl6isme yang sama sekali tidak berhubungan dengan perl5 dalam 13 tahun terakhir; mungkin perlu dicoba.)
Mark Reed

@ MarkReed Saya setuju bahwa saymungkin lebih mudah dibaca dalam kasus ini, terutama bagi mereka yang kurang terbiasa dengan perl.
Primo

9

R

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

... walaupun R ditulis terutama dalam C ... jadi mungkin beberapa baris kode C di belakang 2 baris kode R itu.


2
Itu (atau yang serupa) benar untuk hampir semua jawaban di sini.
JLRishe

8

Objektif-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
Apa? Silakan tulis versi Swift. Omong kosong braket persegi itu menyakiti mataku :)
Tuan Smith

2
Hore for []! Juga, kita harus benar-benar menambahkan versi Smalltalk;)
Bersaelor

@MisterSmith Swift menjawab sekarang tersedia di sini .
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]

Anda bisa lolos dengan melakukan http :: data di dalam put. Tidak perlu membuat variabel sementara. Dan saya juga memformatnya dengan meletakkan baris baru dan membuat indentasi setiap [. Tapi itu pilihan gaya.
Slebetman

7

Pergi

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 kode ini membaca seluruh sumber ke dalam memori, jadi coba gunakan regexp.FindReaderIndexuntuk mencari dalam aliran, yang akan membuat aplikasi antipeluru.


6

CJam

CJam tidak memiliki regex jadi saya harus menggunakan pendekatan yang berbeda dalam hal ini:

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

Saya pertama-tama mengonversi semua 'menjadi ", lalu saya membagi semua ", mengambil setiap string alternatif dan akhirnya memfilter daftar itu untuk string yang dimulai dengan http://atau https://. Setelah itu, cukup cetak setiap string yang difilter pada baris baru.

Cobalah menggunakan juru bahasa Java seperti

java -jar cjam-0.6.2.jar file.cjam

di mana file.cjam memiliki isi kode di atas.


9
Tidak tahu tentang bagian yang dapat dibaca ... tidak tahu Cjam memiliki fungsionalitas web
Def

Jika Anda ingin golf itu ... ''/'"f/:+untuk ''/'"*'"/'"f/0f=.
jimmy23013

... tunggu, kenapa '"f/0f=ada? Apakah itu seharusnya melakukan sesuatu ( 2%misalnya)?
jimmy23013

6

F #

Kode ini bisa jadi jauh lebih pendek tetapi saya akan menulis sesuatu seperti ini jika saya pernah berharap harus membaca atau menggunakan kode ini lagi sehingga memiliki banyak anotasi jenis yang tidak perlu. Ini menunjukkan penggunaan pola aktif matchValue untuk memungkinkan pencocokan pola terhadap tipe standar CLR Pertandingan

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)

Sunting Saya menjadikan getLinks fungsinya sendiri


Saya sangat suka bagaimana Anda menggunakan anotasi jenis. Saya pikir nilai penamaan untuk menggambarkan apa yang Anda kembalikan adalah ok, tetapi nama fungsinya cukup ekspresif: getHTML dan nilai html, getLinks, dan nilai tautan. Dua baris terakhir mungkin tautan |> Seq.iter (printfn "% s")
MichalMa

@MichalMa Saya setuju bahwa nama fungsi cukup ekspresif sendiri, variabel html dan tautan ada karena alasan pragmatis: jadi ada tempat untuk menetapkan breakpoint. Saya menggunakan for for alih-alih List.iter hanya karena saya suka cara membaca lebih banyak, meskipun dalam repl saya mungkin akan menggunakan List.iter.
SourceSimian
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.