Debunking Stroustrup'un “C ++ yalnızca büyük, karmaşık programlar içindir”


161

Stroustrup kısa süre önce C ++ ile ilgili popüler mitleri gözden düşüren bir dizi yazı yayınladı . Beşinci mit: “C ++ sadece büyük, karmaşık, programlar içindir”. Bunu boşaltmak için, bir web sayfasını indiren ve ondan bağlantılar çıkaran basit bir C ++ programı yazdı . İşte burada:

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

Stroustrup'a gerçekte küçük ve okunabilir bir programın ne olduğunu gösterelim .

  1. İndir http://www.stroustrup.com/C++.html
  2. Tüm bağlantıları listele:

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

Herhangi bir dili kullanabilirsiniz, ancak üçüncü taraf kütüphanelerine izin verilmez.

kazanan

Oyların kazandığı C ++ cevabı , ancak kurallara uymayan yarı-üçüncü parti bir kütüphaneye dayanıyor ve başka bir yakın rakip Bash ile birlikte , saldırıya uğramış bir HTTP istemcisine güveniyor (HTTPS ile çalışmaz, gzip, yönlendirmeler vs.) Öyleyse Wolfram açık bir kazanan. Boyut ve okunabilirlik açısından yaklaşan bir başka çözüm de PowerShell'dir (yorumların iyileştirilmesiyle birlikte), ancak fazla dikkat çekmedi. Ana dilleri ( Python , C # ) da oldukça yaklaştı.


43
Her biri için daha kötü olarak adlandırıldım. OP'nin hedefi denemek ve bir şekilde Stroustrup'un yanlış olduğunu kanıtlamak değilse, değerlendirmenize katılıyorum. Ancak sorunun tamamı, "en sevdiğiniz dil" in bu 50 satırdaki C ++ ile aynı şeyi daha az kod satırında nasıl yapabildiğini göstermektir. Sorun, örneklerin hiçbirinin aynı şeyi yapmamasıdır. Özellikle, cevapların hiçbiri hata kontrolü yapmaz, cevapların hiçbiri yeniden kullanılabilir işlevler sunmaz, cevapların çoğu tam bir program sunmaz. Stroustrup örneği bunların hepsini sağlar.
Dunk

19
Üzücü olan, web sayfasının UTF-8 bile geçerli olmadığı . Şimdi bunun üzerinde çalışmalıyım, sunucu reklamlarına rağmen Content-Type: text/html; charset=UTF-8... Ona e-posta göndereceğim.
Mısır,

27
@Dunk Diğer örnekler yeniden kullanılabilir işlevler sağlamaz çünkü bu işlevlerin tüm işlevselliğini tek bir satırda tamamlarlar ve bütün bir işlevi kendi başlarına yapmanın bir anlamı yoktur ve C ++ örneği herhangi bir hata denetimi yapmaz. Bu, doğal olarak neredeyse aynı şekilde ele alınmaz ve "tam program" ifadesi neredeyse anlamsızdır.
Jason

16
“Herhangi bir dili kullanabilirsiniz, ancak üçüncü taraf kütüphanelerine izin verilmez.” Bunu göz önünde bulundurarak adil gereklilik olduğunu sanmıyorum boost/asiohangi oraya kullanılır ise bir üçüncü taraf kitaplığı. Yani, standart kütüphanesinin bir parçası olarak url / tcp alma özelliğini içermeyen diller nasıl rekabet edecek?
greatwolf

Yanıtlar:


115

volfram

Bu tam hile gibi geliyor

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

Bu yüzden sadece üstüne biraz dürüst ayrıştırma ekleyin

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

49
Hayır, burada hile görmüyorum. Bu zorluk, dilin en iyisini ortaya çıkarmakla ilgilidir. Ve bu ilk satır "küçük ve okunabilir" ifadesinin özüdür.
Martin Ender

Ftp bağlantılarını yakalamak hakkındaki aptalca tartışmaları görmezden gelebilecek bir cevap. Parlak.
Seth Battin,

Bu kesin çözümü sunmak için buraya geldik, başkalarının da takdir ettiğini görmek bizi memnun etti.
Michael Stern


6
@DavidMulder Teknik olarak, boşluk şu anda geçerli değil, çünkü oy dağılımı + 41 / -21'dir (ve boşluk deliği sorusu, en az iki oy kadar en fazla iki oylama varsa, boşlukların kabul edildiğini belirtir). Kuşkusuz, ama yine de yakın bir arama. ;) Ayrıca, bu bir popülerlik yarışmasıdır, bir golf kodu değil ve özellikle, bunun belirli bir dilde ne kadar kolay yapılabileceğini gösteren bir pop-con'dur, bu yüzden boşluk deliğinin gerçekten geçerli olmadığını düşünüyorum. Yine de bu meydan okuma (meydan okuma temel olarak sorduğu için).
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";
}

Asıl eksiklik, boost :: asio'nun garip doğasıdır, daha iyi bir kütüphane ile daha da kısa olabileceğinden eminim.


166
Komik, "üçüncü taraf kütüphaneleri yok" demek, Python'un hala import urllib2, C3 hala olabilir using System.Net, Haskel olabilir import Network.HTTP, ancak bir C ++ kodlayıcısının #include <boost/asio.hpp>, özel amaçlı bir C ++ (ve C!) Kitaplıklarının metrik bir parçası olduğu için mazeret göstermesi gerektiği anlamına gelir. seçilebilecek bir şey, sadece komisyonun belirli bir kişiyi zorla besleme zahmetine girmediği için utanılacak bir şey ...
DevSolar

19
@DevSolar neredeyse bu yorum için size başka bir oy vermesi için ikinci bir hesap oluşturmaya gitti
kullanıcı

15
@DevSolar System.Netzorunlu değil, dilde bulunan tüm .NET önerilerini izleyen sadece yüksek kaliteli bir kütüphane. Alternatif uygulamalar var, ancak standart kütüphanede HTTP desteği olması, basit uygulamalar yazmanın basit olduğu anlamına gelir, üçüncü parti kütüphaneler arasında daha iyi birlikte çalışabilirlik anlamına gelir, daha az bağımlılık anlamına gelir, cepheler için kolay uygulama anlamına gelir vb. Olmadan bir dünya hayal edin std::string, herkesin nasıl kullandığını hayal edin kendi kütüphaneleri, onunla birlikte gelen tüm zorlukları hayal edin.
Athari

17
@DevSolar: urllib2olduğu değil 3. parti. <iostream>C ++ 'ta olduğu gibi stdlib'dedir . urllib2Python'da her zaman<boost/asio.hpp> C ++ 'dan farklı olarak kullanılabilir . 3. parti modülleri kullanmamıza izin verilirse; Ben kullanırsınız lxmlveya BeautifulSoupPython.
jfs

22
Ayrıca, buradaki en önemli yorumun, C ++ 'ın standart kütüphanelerinde diğer diller kadar çok şeyi standartlaştırmadığı, ancak dillerde standart olan birçok aynı görev için hala yaygın olarak kullanılan sağlam taşınabilir kitaplıklar olduğunu düşünüyorum. python gibi ve bu liblerin bazıları neredeyse fiilen bir standart. Ve bunun bir kısmı C ++ 'nın küçük ikili ve küçük kütüphaneli gömülü sistemleri hedefleyebilmesinin sonucudur.
Peter Cordes

85

Linux / OS X'te Saf Bash (harici yardımcı program yoktur)

HTTP istemci yazılımı bilinen bir şekilde şişirilir. Bu tür bağımlılıkları istemiyoruz. Bunun yerine uygun başlıkları bir TCP akışından aşağı indirebilir ve sonucu okuyabiliriz. Sonucu ayrıştırmak için grep veya sed gibi arkaik programları aramanıza gerek yok.

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 - Sanırım daha okunaklı olabilir ...


1
Bunun için de unix dosyasını kullanarak borular için tutamaçları kullanın.
javadba

2
Vay canına, hiçbir zaman bunu dış yarar olmadan yapabileceğini düşünmedim. Her ne kadar benim basamağım LFS'deki 3.2.17 gibi gözükse de, küçük bir modası geçmiş, bu yüzden bunu desteklemiyor mapfile:)
Ruslan

@ Ruslan Yep, mapfilebash 4.x ile birlikte gelir. Aynı şey bir while readdöngü ile de tamamen yapılabilir .
Dijital Travma,

3
@Ruslan while readyerine değiştirdim mapfile. Sanırım daha taşınabilir ve daha okunaklı.
Dijital Travma,

1
OS X üzerinde de çalışır!
Alex Cohn

65

Python 2

import urllib2 as u, re
s = "http://www.stroustrup.com/C++.html"
w = u.urlopen(s)
h = w.read()
l = re.findall('"((http)s?://.*?)"', h)
print l

Lame, ama çalışıyor


9
Neden bu çağrıların çoğunu zincirlemiyorsunuz? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Sahte Adı

13
Kısa ama deyimsel değil (okunabilirlik Python'da sayılır)
jfs

24
Hmmm ... eğer tüm kodum bu örnekteki hataları görmezden gelirse, çalışmamın% 75 ila% 90'ı üzerinde çalıştığım her projede zaten yapılmıştı.
Dunk

20
@Dunk: Örneğin bir istisna yakaladığını varsayalım (örn urlopen(). Den ). Çarpma ve ölme dışında, böyle bir istisna dışında ne yapmalı? Eğer yine de çöküp ölecekse, neden Python'un çökmeyi-ölmeyi idare etmesine ve istisnayı tamamen bırakmamasına izin vermiyoruz?
Kevin

8
@Dunk: Başkasının Python kodunu kullanarak olsaydı, bunun yerine ederdim değil yakalamak urlopen(diyelim) onları yakalamak ve çağrı daha hataları sys.exit("something's borked!"). İkincisini yaparlarsa, yakalamak zorundayım SystemExitki bu hiç eğlenceli değil.
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
Kullanabilir var htmlve muhtemelen var matchbirkaç karakteri tıraş etmek için kullanabilirsiniz .
Superbest

15
@Superbest İsimleri tek karakter yapabilir ve htmldeğişkenlerden tamamen kurtulabilirim , ama peşinde olduğum şey bu değil.
Athari

6
@ Süper best code-golf değil . : D
Kroltan

5
Eh, aynı zamanda okunabilirliği artırır. varKod anlambilimini etkilemeyecek zaman kullanmamak için bir neden var mı ?
Superbest

6
@ Süper best: "okunabilirliği arttırır" özneldir. Şahsen, değişkenin türünü açıkça belirtmenin okunabilirliği artırdığını düşünüyorum (genellikle bu koddaki gibi). Yine de bunu tartışmak istemiyorum; Sadece alternatif görüşlerin varlığına işaret etmek istiyorum.
Cornstalks

54

"Üçüncü taraf yok" yanlış bir şey

"Üçüncü taraf yok" varsayımının bir yanlışlık olduğunu düşünüyorum. C ++ geliştiricilerini etkileyen belirli bir yanılgıdır, çünkü C ++ 'ta yeniden kullanılabilir kod yapmak çok zordur. Hiç bir şey geliştirirken, küçük bir senaryo olsa bile, kullanabileceğiniz kodlardan her zaman yararlanabileceksiniz.

Mesele şu ki, Perl, Python, Ruby gibi dillerde (bir kaç isim), başkasının kodunu tekrar kullanmak sadece kolay değil, aynı zamanda çoğu insanın çoğu zaman nasıl kod yazdığıdır.

C ++, neredeyse imkansız bakımı-uyumlu-ABI gereklilikleriyle, çok daha zorlu bir iş yapıyor, kodun canavarca bir deposu ve bunun dışında çok az bir bestecilik olan Boost gibi bir projeyle sonuçlanıyor.

Bir CPAN örneği

Sadece eğlenmek için, burada html'yi ayrıştırmak için regex kullanmaya çalışmak yerine, html'nin uygun şekilde ayrıştırılmasıyla CPAN tabanlı bir örnek verilecek.

#!/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
3. parti liblerinin amacına değinmek için oy verin, ancak: C ++ 'ta yeniden kullanılabilir kodlar yapmak başka bir dilde olduğu kadar kolay. Kullanılması ve özellikle bulmakta yeniden kod biraz daha sert, fakat yeniden edilir ciddiye sorunlu olan tek şey olabilir derlenmiş eserler, ancak bu genellikle vb Perl, gibi yorumlanır dillerde olmayan bir konu
Martin Ba

4
Bir benzetmeyi genişletmek için, Boost daha çok CPAN gibidir - seç ve seç. CPAN'a "korkunç bir kod deposu" demiyorsunuz, çünkü orada kullanmadığınız çok şey var?
Martin Ba,

22
CPAN , bu dört kelimenin herhangi bir makul tanımı ile 'kodun canavarca deposudur'.
jwg

3
@MartinBa C ++ 'ın derlenmiş bir dil olması nedeniyle, tüm çalıştırılabilir dosyaların tüm bağımlılık yığınını yeniden oluşturmalarını gerektiren bir dil olması nedeniyle, ABI uyumluluğunu korumak zor olduğundan kodun yeniden kullanılabilirliğini ciddi şekilde engelliyor. C ++ 'ta yeniden kullanılabilir bir kütüphane oluşturmak için, kendinizi her zaman ABI ile uyumsuz değişikliklere zorlamadığınızdan emin olmak için çok uzun sürelerden geçmeniz gerekir.
Daniel Ruoso

6
@ MartinBa çünkü basit bir görevi gerçekleştirmek istediğiniz her zaman tüm evreni yeniden inşa etmek zorunluluktur.
Daniel Ruoso,

47

UNIX kabuğu

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

Ayrıca bir ftp://link bulur :)

Başka bir yol, ://sözdizimine güvenmeden :

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

38
Bir web sayfasını indirmek için bir web tarayıcısı kullanmak iş için doğru bir araç veya -1 için sorun değil, çünkü zorluk, blahblahblah yapmak için bir program yazmak ve bunu yapmak için bir program çağırdığınız için çünkü suçlama.
David Richerby

2
Bence vaşak veya kıvrım ile vaşağı değiştirmek daha iyi olur. Bir web sayfasını indirmek için daha yaygın olarak kullanılırlar.
Pavel Strakhov

4
@PavelStrakhov Tam olarak lynx'i seçtim, çünkü benden özel bir şey yapmadan bağlantıları silebiliyordu :)
Ruslan

2
@SteveJessop "özel" ile aslında ayrıştırma veya yeniden düzenleme ya da her neyse demek. Lynx ile sadece bağlantıların listesini okutuyorum (ki bu kıvrılıp yazmıyor) ve numaralandırmayı kaldırıyorum. Hile yaptığını veya her neyse onu düşünebilirsiniz, ancak { çıktıyı hassas bir şekilde ayarlamak için {gerekli olanı neredeyse mükemmel yapan aleti kullanmanın} eğlenceli olduğunu düşündüm .
Ruslan

7
"ancak üçüncü taraf kütüphanelerine izin verilmiyor" . lynxİşlevsel olarak, bu senaryoda üçüncü taraf bir kütüphaneye eşdeğer olduğunu iddia ediyorum .
Dijital Travma

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

Bu kod, biçimlendirilmemiş bir listedeki bir sayfada yalnızca mutlak bağlantıları görüntülemek için bir kullanıcı stili olarak kullanılabilir. Tarayıcınız minimum yazı tipi boyutunu zorlarsa doğru çalışmayabilir.

İle doğru çalışır http://www.stroustrup.com/C++.html(not !importantüzerine background). Daha fazla stil içeren diğer sayfalarda çalışmak için genişletilmesi gerekir (daha fazla özelliği sıfırlayın, özellikleri önemli olarak işaretleyin vb.).

Karmalarla başlayan intrapage bağlantılar dışında göreceli bağlantılar içeren alternatif sürüm (ne yazık ki sabit kodlanmış mutlak bir bağlantıya dayanır):

* {
  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
Bu gördüğüm en kötü şey. +1
Emmett R.

1
Bu güzel ve tamamen korkunç. +1
ricdesi

36

Clojure

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

27
Slurp ?! Clojure'u öğrenmem gerek.
11684

10
@ 11684 - Clojure da adlandırılan standart işlevlere sahiptir spit, zipperve lazy-cat:-) ...
Bob Jarvis

2
Vay, sanırım bu geç Yeni Yıl Kararı olacak. @ 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
Bu kodun ne kadar küçük ve büyük oranda okunaklı olduğu göz önüne alındığında, daha fazla oy kullanmadığı için biraz kirilmis durumdayım. Aferin.
Spacemoose

28

Scala

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

8
her şeyi bir satırda
topla

Ne hakkında ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl - Bu bir ifadedir , sadece bir satır değil. Tüm satır sonlarını C ++ kodundan silebilirsiniz, ancak bu, görevi tek bir ifadede yapmakla aynı şey değildir.
DaoWen

4
@DaoWen: Üzgünüz, ama express-vs-line ifadeleri başlamak aptalca gidiyor. Bazı functorları ekleyin ve C ++ 'ı da yapabilirsiniz. Ancak bu, lib'lerin “verildiği” ve “içinde sıfır kod” olduğu düşünülen bir soru. Onu bir çizgide paketlemenin okunabilirliği arttırdığı gerçeğini değiştirmez. Biri onu hala tek bir ifade olarak tutabilir ve sadece birkaç satır halinde yeniden biçimlendirir. Bu benim amacım. Aptalca paketleme - C ++ da yapabilir. Birisi "aptal paketleme" kutusundan çıkmak istiyorsa, kodu satır sayımı değil okunabilirlik için biçimlendirmelidir.
quetzalcoatl

3
@quetzalcoatl Tobias, onu takip etmemiz için oraya bağlantı koymadı. Bu cevabın yazara neden sonuçlarında olmadığını soruyordu.
JLRishe

25

PHP 5

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

5
Önerilen düzenlemeler: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(şu anda bir hata); Kaldır array_unshift($m);(şu anda bir hata, muhtemelen array_shiftbunun yerine) print_r($m);print_r($m[1]);(sadece URL'leri çıkar).
primo

Sabit, girişiniz için teşekkürler
David Xu

@DavidXu Düzeltmediysen hariç ...?
Shahar

şimdi düzeltildi.
David Xu,

25

Güç kalkanı

Tam nitelikli URL’lerin (JavaScript, CSS, vb. Dahil) metin araması :

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

Veya yalnızca bağlantı etiketlerinde bağlantı almak için (göreli URL’leri içerir):

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

Yorumlardan daha kısa sürümler:

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

6
Herkes merak ediyorsa, (PS3 +) iwriçin takma Invoke-WebRequestaddır.
Athari

8
Sen koleksiyonlarını düzleştirmek ve yapılacak PowerShell en şevk kötüye olabilir: (iwr "http://www.stroustrup.com/C++.html").Links.href(veya (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"yalnızca mutlak URI en için)
Mathias R. Jessen

1
Bu oldukça kullanışlı!
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]); }
}

Orijinal örneğe liste benzer hale getirmek için, boru programın çıktısı yoluyla olabilir | sort | uniqveya bunun yerine ekleyebilir import std.arrayve çizgiyi değiştirmek .filter!("a")){ writeln(_.front[1]); }bu işe: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Ancak, yalnızca bu kodu denediğimi ve doğru ya da "deyimsel" olduğunu kanıtlamadığımı unutmayın. :)
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
İşe yarayıp require('http').getyaramadığını merak ediyorum . Eğer öyleyse, var deyimini kaldırabilir ve başka bir satırı kısaltabiliriz.
Unihedron

@Unihedro Yapar.
TimWolla

9
@Unihedro Yapar, ama bu bir golf yarışması değil.
cPu1

Herhangi bir yakalama grubu kullanmanıza gerek yoktur.
Ry

Bence bu bir çerçeve adı değil, JavaScript.
mr5

20

Yakut

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

1
Regex'iniz başarısız olacak, kullanmanız gerekir %r{"(https?://[^"]+)"}. Ayrıca Net::HTTP.get('www.stroustrup.com', '/C++.html')isteği kısaltmak için de kullanabilirsiniz (ve okunabilir halde tutunuz). Yani bütün kod tek satırda olabilir (okunabilir tutarak): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Çalıştır ruby -rnet/httpve hatta hatta ihtiyacın yok require 'net/http'.
Hauleth,

20

Haskell

"\w"Text.Regex.Posix’de bazı sıkıntılar

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

Neden resultbelirtilen tür açıkça belirtiliyor? İçinde kullanımı tamamen sınırlandırılmalıdır unlines.
John Dvorak

1
Bu, biraz kurallarını germek gibi görerek ne yok Network.HTTPne de TextRegex.Posixbulunmaktadır basepaketin. (Haskell Platformu'nda ve elbette Hackage'da olsalar da, bu yüzden ...)
saat

1
@JanDvorak, ghci ile yazmaya başladım (muhtemelen değişmeden göndermeliyim). Ancak notunuz önemlidir, teşekkürler.
vlastachu

@leftaroundabout, bilmiyordum. Temel paketi kullanmış olsaydım yapamadım gibi görünüyor.
vlastachu

networkher baseikisinde de değil , bu yüzden kendi soket bağlayıcılarınızı yuvarlamak için tasarruf edin, bunu yapmanın pratik bir yolu yoktur base.
Lambda Perisi

18

PHP

Söyleyebileceğim kadarıyla, modern PHP kurulumlarının çoğu DOM işlemesi ile birlikte geliyor, işte aslında HTML'nin içindeki çapaları geçen bir tane:

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

İç döngü şuna kısaltılabilir:

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

Aslında bununla gelmek istedim (buradaki ilk cevabım olarak). İlk önce bunu yaptınız, işte +1 (hataya açık bir Regex kullanmamak için)! İpucu: Bir budalayı kullanabilirsiniz 1yerine trueyönelik in_arraysıkı arama. Parantezleri atlayabilirsiniz. Tamamen emin değilim, ama şunu bırakabilirim httpve sadece bırakabilirsin ://( plana bakmadan ). .
Kaiser

Ve: Başka bir olasılık if ( ) {}lehine düşürmek olacaktır in_array() and print $url.PHP_EOL. Ama evet, en iyi okunabilirlik için başka bir +1 (eğer yapabilseydim) elde edersiniz :)
kaiser

Sadece örneğinizi denedim ve katı standartlar için bir hata oluştu (PHP 5.4). Kaynaktaki gibi görünüyor, eksik bir noktalı virgül ile bozuk veya yanlış biçimlendirilmiş bir bağlantı var. Kullanarak hata raporlamayı kapatabilirsiniz @\DOMDocument. Sadece denedim ve çalıştığını onaylayabilir.
kaiser

Hayır, bu yanlış olan belgeler; teknik ::loadHTMLFile()olarak statik olarak aramamanız ve @yalnızca bu eserleri gizlemek için kullanmanız gerekmiyor .
Jack

2
Bu kesinlikle en "doğru" çözümlerden biri, üretimde kullanımda görebildiğim tek çözümden biri. iyi iş
Jordon Biondo

14

Unix Kabuğu

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

İtiraf etmeliyim ki, bir hatta birden fazla bağlantı varsa işe yaramaz.


1
curl http://www.stroustrup.com/C++.htmlbirkaç karakter kaydeder.
l0b0

7
"ancak üçüncü taraf kütüphanelerine izin verilmiyor" . Sanırım wgetGNU olduğundan (bash gibi), bunun üçüncü taraf olmadığını iddia edebilirsiniz. Ama curlkesinlikle üçüncü taraf.
Dijital Travma

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

4
@ TobiasKienzler Stroustrup'un orijinal kodu ya onları bulamıyor galiba
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
Cevaplarınızdaki kodu doğru bir şekilde formatlayabilir misiniz? En az okunabilen kod için rekabet değildir. En azından yatay kaydırma çubuklarından kaçınmak için formatlayabilirsiniz.
Athari

Eğer kullanıyorsanız, Scannerdoğrudan bağlantılar için regex desenini işlemesini sağlayabilirsiniz ve Scannersonuçları gözden geçirin .
Holger

5
Evet .. bu senin için java. Kod golf için kullanmak cesur bir girişimdir.
javadba

4
Asla C ++ 'dan daha kısa bir java çözümü göreceğimi düşünmedim!
Slebetman

2
Son yorumuma düzeltme: Bunun Java'da yazılabilecek en kısa ve en temiz kod olduğunu kabul etmeliyim. Lamx'larla daha da kısaltılabilecek SAX ayrıştırıcı bir yaklaşım denedim, ancak web sayfası XHTML değil ve ayrıştırıcı istisnalar oluşturuyor. Regex gitmek için tek yoldur.
Bay Smith,

11

harika

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

? Kullanılarak geliştirilebilir. NPE'lerden kaçınmak için operatör
Chris K,

2
@ChrisKaminski ve hataları kontrol etmek için buradaki ilk kişi (Bjarne'nin yanında)? asla! Bunun yanında: Burada sadece IO ile ilgili istisnalar görüyorum. NPE'yi nerede görüyorsun?
cfrick

findAll () null döndürürdü, hayır? Yoksa boş bir liste döndürür mü? Hala Groovy için biraz yeni. EDIT: nm, findAll () gibi boş bir liste döndürür. O Groovy adamları çok akıllıydı. :-)
Chris K,

11

SQL (SQL Her Yerde 16)

Web sayfasını almak için saklı bir prosedür tanımlayın

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

Tek bir sorgu kullanarak sonuç kümesini üret

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;

Sınırlamalar: Bu 256'ya kadar bağlantı üretir. Daha fazla bağlantı varsa, 256'yı uygun bir değere yükseltin.


2
SQL'de golf olacağına inanmıyordum ... şu ana kadar.
vaxquis

Anladım ... "bağlantılar". :-)
SAP Canada'da Jack

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
Sanırım bu CoffeeScript / Node? Sanırım bunu belirtmelisin ...
John Dvorak

Vay. Bu çok okunaklı.
Slebetman

@slebetman kesinlikle küçük olsa da
John Dvorak

@slebetman Yeah CoffeeScript, JavaScript'ten çok daha okunaklı :) :) Tüm kaşlı ayraçlardan kurtulduğuma sevindim. :) :)
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
Alan ayırıcıdan ve kayıt ayırıcı değişkenlerinden kaçınıldıysa ve az önce şunu yaparsanız kod daha açık olacaktır: {"$ _ \ n"} haritayı yazdır $ $ -> content = ~ m <"(https?: //.+ ?) "> g;
Daniel Ruoso,

@DanielRuoso kabul etti.
primo

ya da hatta use v5.10;ve say for $response->content...
Mark Reed,

Sanırım kendi başına. Desteklenen perl6 özelliklerinden bazıları sorunlu (akıllı eşleştirme, sana bakıyorum), ancak sayoldukça kullanışlıdır ve bence burada daha açık. (Ayrıca, son 13 yıl içerisinde perl5 için tamamen alakasız-perl6ism iyileştirmeler yapıldı; göz atmaya değer olabilir.)
Mark Reed

@MarkReed sayBu durumda, özellikle perl ile daha az tanıdık olanlar için muhtemelen daha okunaklı olduğuna katılıyorum .
primo

9

R,

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

... R esas olarak C dilinde yazılsa da, muhtemelen bu 2 satır R kodunun arkasındaki birkaç satır C kodu.


2
Bu (veya benzer bir şey) buradaki tüm cevaplar için geçerlidir.
JLRishe

8

Objective-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
Ne? Lütfen Swift versiyonunu yazınız. Bu köşeli ayraç saçmalık gözlerimi incitiyor :)
Mister Smith

2
[] İçin hurra! Ayrıca, bir Smalltalk versiyonunu da tamamen eklemeliyiz;)
Bersaelor

@MisterSmith Swift şimdi burada cevap .
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]

Kovanların içindeki http :: verilerini kullanarak kurtulabilirsiniz. Geçici bir değişken oluşturmanıza gerek yok. Ve ayrıca yeni çizgiler ekleyerek ve her yere girerek biçimlendirirdim [. Ama bu bir stil seçimi.
Slebetman

7

Git

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 bu kod kaynağın tamamını belleğe okur, bu nedenle regexp.FindReaderIndexuygulamayı kurşun geçirmez hale getirecek akışta aramayı kullanmayı düşünün .


6

CJam

CJam'ın regex'i olmadığından, bu konuda farklı bir yaklaşım kullanmak zorunda kaldım:

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

Ben her şeyden önce dönüştürmek 'için "o zaman tümü üzerinde bölünmüş, "her alternatif dize almak ve sonra nihayet başlayarak dizeleri için bu listeye filtre http://veya https://. Bundan sonra, filtrelenen her dizeyi yeni bir satıra yazdırmanız yeterlidir.

Gibi Java tercümanı kullanarak deneyin

java -jar cjam-0.6.2.jar file.cjam

Burada file.cjam yukarıdaki kodun içeriğine sahiptir.


9
Okunabilir kısmı bilmiyorum ... Cjam'ın web işlevselliği olduğunu bilmiyordum
Def

Eğer golf oynamak istiyorsan ... ... ''/'"f/:+için ''/'"*'"/'"f/0f=.
jimmy23013

... bekle neden '"f/0f=var? Bunun bir şey yapması mı gerekiyor ( 2%örneğin)?
jimmy23013

6

F #

Bu kod çok daha kısa olabilirdi, ancak bu kodu tekrar okumak ya da kullanmak zorunda kalırsam, bu yüzden pek çok gereksiz tip ek açıklamasına sahip olsaydım, bunun gibi bir şey yazardım. Bu aktif bir desen kullanımını gösterir MatchValue standart CLR tipi karşı desen eşleştirme etkinleştirmek için Match

open System.Net

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

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

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

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

Edit GetLinks'i kendi işlevi yaptım


Yazı tipi açıklamalarını nasıl kullandığını gerçekten seviyorum. Döndüğünüzü tanımlamak için değerleri adlandırma bence, ancak işlevin adı yeterince ifade edici: getHTML ve html değeri, getLinks ve links değeri. Son iki satır bağlantılar olabilir>> Seq.iter (printfn "% s")
MichalMa

@MichalMa Fonksiyonun adının kendi başına yeterince anlamlı olduğuna katılıyorum, html ve links değişkenleri pragmatik nedenlerle var: yani bir kesme noktası ayarlayabilecek bir yer var. List.iter yerine for döngüsünü kullandım, çünkü okudukları yolu daha çok sevdim çünkü bir repl'de muhtemelen List.iter kullanıyordum.
SourceSimian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.