Stroustrupの神話「C ++は大規模で複雑なプログラム専用」を暴く


161

Stroustrupは最近、C ++に関する人気の神話を暴く一連の投稿を投稿しました。5番目の神話は、「C ++は大規模で複雑なプログラム専用です」です。それを暴くために、彼はWebページをダウンロードし、そこからリンクを抽出する簡単なC ++プログラムを書きました。ここにあります:

#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に、小さくて読みやすいプログラムが実際に何であるかを示しましょう。

  1. ダウンロード http://www.stroustrup.com/C++.html
  2. すべてのリンクをリスト:

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

任意の言語を使用できますが、サードパーティのライブラリは許可されていません。

勝者

C ++の回答は投票で勝ちましたが、セミサードパーティのライブラリ(ルールで禁止されています)に依存しており、別の近い競合Bashと一緒に、ハッキングされたHTTPクライアントに依存しています(HTTPSでは動作しません) gzip、リダイレクトなど)。したがって、Wolframは明確な勝者です。サイズと読みやすさの点で近づいているもう1つのソリューションは、PowerShell(コメントを改善したもの)ですが、あまり注目されていません。主流の言語(PythonC#)も非常に近くなりました。


43
彼自身のそれぞれに、私はより悪いと呼ばれてきました。OPの目標が、Stroustrupが間違っていることを何とかして証明することではなかった場合、あなたの評価に同意します。しかし、質問の全体的な前提は、「お気に入りの言語」が、はるかに少ないコード行でこの50行のC ++と同じことをどのように行えるかを示すことです。問題は、どの例も同じことをしないということです。特に、エラーのチェックを実行する回答はなく、再利用可能な機能を提供する回答もありません。ほとんどの回答は完全なプログラムを提供しません。Stroustrupの例は、それらすべてを提供します。
ダンク

19
悲しいことに、彼のWebページは有効なUTF-8でさえありません。彼のサーバー広告にもかかわらず、今私はそれを回避する必要がありますContent-Type: text/html; charset=UTF-8...私は彼に電子メールを送るつもりです。
トウモロコシ茎

27
@Dunk他の例は、再利用可能な関数を提供しません。これらの関数の機能全体を1行で実行し、関数全体を単独で作成しても意味がなく、C ++の例はエラーチェックを実行しないためです。それはほとんど同じ方法でネイティブに処理されず、「完全なプログラム」というフレーズはほとんど意味がありません。
ジェイソン

16
「任意の言語を使用できますが、サードパーティのライブラリは許可されていません。」私はboost/asioそれサードパーティのライブラリであると考えられていることを考えると、公正な要件だとは思わない。標準ライブラリの一部としてurl / tcpフェッチを含まない言語はどのように競合するのでしょうか?
グレートウルフ

回答:


116

ウルフラム

これは完全な不正行為のように感じます

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

正直な構文解析を上に追加するだけです

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

49
いいえ、不正行為はありません。この課題は、あなたの言語を最大限に引き出すことです。そして、その最初の行は「小さくて読みやすい」という縮図です。
マーティンエンダー

ftpリンクのキャッチに関する愚かな議論を無視できる答え。ブリリアント。
セスBattin

この正確なソリューションを提供するためにここに来ましたが、他の人がそれを高く評価しているのを見て喜んでいます。
マイケルスターン

あなたがdownvoting検討する必要があり、その場合には、@MartinBüttner meta.codegolf.stackexchange.com/a/1078/12130を
デビッド・モルダー

6
@DavidMulder技術的には、投票の内訳は+ 41 / -21であるため、抜け穴は現在有効ではありません(抜け穴の質問には、抜け穴の少なくとも2倍の投票があれば抜け穴が受け入れられると記載されています)。クローズコール、確かに、しかしまだ。;)さらに、これはコードゴルフではなく人気のコンテストであり、特に、特定の言語でこれをどれだけ簡単に行えるかを示すポップコンです。そのため、抜け穴は実際には当てはまらないと思いますとにかくこのチャレンジ(チャレンジは基本的にそれを要求するため)。
マーティンエンダー

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

主な欠点は、boost :: asioの扱いにくい性質です。より良いライブラリを使用すれば、さらに短くなる可能性があります。


166
「サードパーティのライブラリがない」というのは、Pythonがまだimport urllib2、C3はまだusing System.Net、Haskelはまだかもしれないことを意味しますimport Network.HTTPが、C ++コーダーは#include <boost/asio.hpp>、専用の専用C ++(およびC!)ライブラリのメトリッククラットンを持っているかのように言い訳をしなければなりません選択できるのは、委員会があなたに特定のものを強制的に送り込むことを気にしなかったという理由だけで恥ずべきことです
...-DevSolar

19
@DevSolarは、2番目のアカウントを作成して、そのコメントに別の賛成票を投じようとしました。
ユーザーは

15
@DevSolar System.Netは強制されたものではなく、言語に含まれるすべての.NET推奨事項に従った高品質のライブラリです。代替の実装もありますが、標準ライブラリでHTTPをサポートすることは、シンプルなアプリの作成が簡単であることを意味し、サードパーティライブラリ間の相互運用性が向上し、依存関係が少なくなり、ファサードなどの実装が容易になることを意味しstd::stringます。独自のライブラリ、それに伴うすべての困難を想像してください。
アタリ

17
@DevSolar:サードパーティでurllib2はありません<iostream>C ++のようなstdlibにあります。urllib2Python では、C ++ とは異なり、常に使用できます<boost/asio.hpp>。サードパーティのモジュールの使用が許可された場合; lxmlまたはBeautifulSoupPython を使用します。
jfs

22
また、ここで最も重要なコメントは、C ++が他の言語と同じくらい標準ライブラリの内容を標準化していないということだけだと思いますが、言語で標準である同じタスクの多くのために広く使用されている堅牢なポータブルライブラリがまだありますPythonのようなもので、これらのライブラリのいくつかはほぼ事実上の標準です。そしてその一部は、C ++が小さなバイナリと小さなライブラリを備えた組み込みシステムをターゲットにできる結果です。
ピーターコーデス

85

Linux / OS X上のPure Bash(外部ユーティリティなし)

HTTPクライアントソフトウェアは肥大化していることで有名です。こうした種類の依存関係は望ましくありません。代わりに、適切なヘッダーをTCPストリームにプッシュし、結果を読み取ることができます。結果を解析するためにgrepやsedなどの古風なユーティリティを呼び出す必要はありません。

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-もっと読みやすいと思います...


1
このように、Unixファイルハンドルをパイプに使用します。
javadba

2
うわー、外部ユーティリティなしでこれを行うことができるとは思わなかった。LFSでの私のbash 3.2.17は少し時代遅れなので、サポートしていませんmapfile:)
ルスラン

@Ruslan Yep、mapfilebash 4.xが付属しています。同じことはwhile readループでも完全に実行可能です。
デジタル外傷

3
@Ruslanのwhile read代わりに変更しましたmapfile。よりポータブルで読みやすいと思います。
デジタル外傷

1
OS Xでも動作します!
アレックスコーン

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

ラメですが、動作します


9
これらの呼び出しの多くを連鎖させないのはなぜですか?l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
偽の名前

13
それは短いですが、慣用的ではありません(Pythonで読みやすさがカウントされます)
-jfs

24
うーん...すべてのコードがこの例のようなエラーを無視した場合、作業のすべてのプロジェクトで作業の75%から90%が既に完了しています。
ダンク

20
@Dunk:例が(たとえばからurlopen())何らかの例外をキャッチしたとします。クラッシュして死ぬ以外に、このような例外がある場合はどうすればよいですか?とにかくクラッシュして死ぬ場合、Pythonにクラッシュと死を処理させ、例外処理を完全に終了させて​​はどうでしょうか。
ケビン

8
@Dunk:私は他人のPythonコードを使用していた場合、私はむしろ、彼らはあまりいただきたいではないキャッチurlopen(例えば)それらをキャッチし、呼び出しよりもエラーをsys.exit("something's borked!")。後者の場合は、キャッチSystemExitする必要がありますが、これは決して楽しいことではありません。
ケビン

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
を使用してvar html、おそらくvar matchいくつかの文字を削除することができます。
スーパーベスト

15
@Superbest名前を1文字にして、html変数を完全に削除することもできますが、それは私が望んでいることではありません。
アタリ

6
@Superbestはcode-golfではありません。:D
Kroltan

5
まあ、それは読みやすさも改善します。varコードのセマンティクスに影響しないときに使用しない理由はありますか?
スーパーベスト

6
@Superbest:「読みやすさを改善する」は主観的です。個人的には、変数の型を明示的に指定すると読みやすくなります(通常、このコードのように)。ただし、これについては議論したくありません。代替ビューが存在することを指摘したいだけです。
トウモロコシ茎

54

「サードパーティなし」は誤りです

「サードパーティなし」という仮定は誤りだと思います。また、C ++で再利用可能なコードを作成するのは非常に難しいため、C ++開発者を悩ます特定の誤fallです。たとえ小さなスクリプトであっても、何かを開発しているときは、利用可能な再利用可能なコードの断片を常に利用します。

重要なのは、Perl、Python、Rubyなどの言語では、他の人のコードを再利用するのは簡単であるだけでなく、ほとんどの人がほとんどの場合実際にコードを書く方法です。

維持するのがほぼ不可能なABI要件を備えたC ++は、それをはるかに困難な仕事にします。最終的に、Boostのようなプロジェクトになります。

CPANの例

楽しみのために、正規表現を使用してhtmlを解析する代わりに、htmlを適切に解析するCPANベースの例を示します。

#!/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
サードパーティのLIBSのポイントに対処するためのUpvote、しかし:がらくた、作る再利用可能なコードを C ++には、同様に簡単安っぽい他の言語のようです。使用すると、特に見つけ、再利用可能なコードは少し難しいが、再利用され、真剣に問題だ唯一のものかもしれコンパイルアーティファクトを、それは多くの場合などはPerlのようなインタプリタ言語で非問題だ
マーティンBaの

4
類推を拡張するために、BoostはCPANに似ています-選択して選択します。使用しないものがたくさんあるからといって、CPANを「コードの巨大なリポジトリ」と呼んでいませんか?
マーティンBa

22
CPAN 、これら4つの単語の合理的な定義により、「コードの巨大なリポジトリ」です。
jwg

3
@MartinBa私は同意しません。C++はコンパイルされた言語であり、ABIの互換性を維持するのが難しいため、すべての実行可能ファイルが依存関係の完全なスタックを再構築する必要があるため、コードの再利用性が妨げられます。C ++で再利用可能なライブラリを作成するには、常にABI互換性のない変更を強制しないように、非常に長い時間を費やす必要があります。
ダニエルルオーソ

6
@MartinBaは、単純なタスクを実装するたびにユニバース全体を再構築する必要があるため、耐えられないためです。
ダニエルルオーソ

47

UNIXシェル

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

ftp://リンクも見つけられます:)

://構文に依存しない別の方法:

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

38
Webブラウザーを使用してWebページをダウンロードすることが仕事に適しているため+1するのか、それとも-1非難。
デビッドリチャービー

2
lynxをcurlまたはwgetに置き換える方が良いと思います。ウェブページをダウンロードするために、より一般的に使用されます。
パベルストラホフ

4
@PavelStrakhov lynxを選んだのは、特別なことをしなくてもリンクをダンプできるからです。)
Ruslan

2
「特別」による@SteveJessop私は実際に解析または正規表現などを意味します。lynxを使用して、リンクのリスト(curlとwgetはリストしません)をgrepし、番号付けを削除します。あなたはそれが不正行為だと考えるかもしれませんが、出力を微調整するだけで{必要なことをほぼ完璧に行うツールを使用する}ことは楽しいと思いました。
ルスラン

7
「しかし、何のサードパーティのライブラリは許可されません」lynxこのシナリオでは、サードパーティのライブラリと機能的に同等であると主張します。
デジタル外傷

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

このコードは、書式なしリストのページに絶対リンクのみを表示するユーザースタイルとして使用できます。ブラウザが最小フォントサイズを強制している場合、正しく動作しない可能性があります。

http://www.stroustrup.com/C++.html(で注意!importantしてくださいbackground)で正しく動作します。より多くのスタイルを持つ他のページで作業するには、拡張する必要があります(より多くのプロパティをリセットする、プロパティを重要としてマークするなど)。

ハッシュで始まるページ内リンクを除く相対リンクを含む代替バージョン(残念ながらハードコードされた絶対リンクに依存しています):

* {
  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
これは私が今まで見た中で最悪のことです。+1
エメットR.

1
これは美しく、完全に恐ろしいです。+1
ricdesi

36

クロージュア

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

28
丸?み?Clojureを学ぶ必要があります。
11684

10
11684 @ - Clojureのも名前の標準機能を持っているspitzipperlazy-cat:-) ...
ボブ・ジャービス

2
うわー、それは新年の後半の決議になるだろうと思います。@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
このコードが非常にコンパクトで非常に読みやすいことを考えると、これ以上票がないことは少し残念です。よくやった。
スペースムース

28

スカラ

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

8
すべてを1行に
まとめる

どうftp://ftp.research.att.com/pub/c++std/WP/CD2
トビアスキンツラー

22
@quetzalcoatl-これは、1行ではなく1つのです。C ++コードからすべての改行を削除することができますが、それは単一の式でタスク全体を実行するのと同じことではありません。
-DaoWen

4
@DaoWen:すみませんが、expressions-vs-lineの開始はばかげています。ファンクタとC ++を追加して、それもできます。しかし、それは、どのライブラリが「許可」され、「内部にゼロコード」を持っていると見なされるかという問題です。行にまとめて読みやすくするという事実は変わりません。それを単一の式として保持し、それを数行に再フォーマットして、多くを獲得し、..行数以外は何も失うことはありません。それが私のポイントです。愚かなパッキング-C ++でもできます。誰かが「愚かなパッキング」ボックスから抜け出したい場合は、行数ではなく読みやすいようにコードをフォーマットする必要があります。
ケツァルコアトル

3
@quetzalcoatl Tobiasは、私たちがそれに従うためのリンクをそこに入れませんでした。彼はこの答えを書いた人に、なぜ彼の結果にはなかったのか尋ねました。
JLRishe

25

PHP 5

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

5
推奨される編集:'/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(現在エラー); 削除array_unshift($m);(現在はエラーです。おそらくarray_shift代わりに意図したものです); print_r($m);print_r($m[1]);(URLのみを出力)。
プリモ

あなたの入力のための固定された、ありがとう
デヴィッド・徐

@DavidXuあなたがそれを修正しなかったことを除いて...?
シャハール

修正されました!
デビッド徐

25

パワーシェル

すべての完全修飾URL(JavaScript、CSSなどを含む)のテキスト検索:

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

または、アンカータグのみでリンクを取得するには(相対URLを含む):

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

コメントからの短いバージョン:

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

6
誰かが疑問に思うなら、iwrInvoke-WebRequest(PS3 +)のエイリアスです。
アタリ

8
あなたは、コレクションを平らにするためのPowerShellの意欲を乱用して行うことができます:(iwr "http://www.stroustrup.com/C++.html").Links.href(または(iwr "http://www.stroustrup.com/C++.html").Links.href-match":"唯一絶対URIのため)
マティアスR.ジェッセン

1
それはかなり便利です!
ジャスティンダンラップ

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

リストを元の例と同様にするために、プログラムの出力をパイプ処理する| sort | uniqか、代わりに次import std.arrayの行.filter!("a")){ writeln(_.front[1]); }を追加および変更できます.filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }。ただし、このコードを試しただけであり、それが正しいまたは「イディオマティック」であることを証明していないことに注意してください。:)
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
うまくrequire('http').getいくのだろうか。もしそうなら、varステートメントを捨てて別の行を短くすることができます。
ユニヘドロン

@Unihedroそうです。
ティムウォラ

9
@Unihedroありますが、これはゴルフのコンテストではありません。
cPu1

キャプチャグループを使用する必要はありません。
Ry-

フレームワーク名ではなくJavaScriptだと思います。
mr5

20

ルビー

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

1
正規表現は失敗します%r{"(https?://[^"]+)"}。使用する必要があります。また、Net::HTTP.get('www.stroustrup.com', '/C++.html')リクエストを短縮するために使用することができます(そしてそれを読みやすくします)。したがって、コード全体を1行に収めることができます(読みやすくする)puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"})。で実行するとruby -rnet/httprequire 'net/http'ラインさえ必要ありません。
ハウレス

20

ハスケル

"\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

のタイプがresult明示的に指定されているのはなぜですか?での使用によって完全に制約される必要がありますunlines
ジョンドヴォルザーク

1
これにより、ルールが少し拡張され、パッケージ内にもパッケージ内にNetwork.HTTPTextRegex.Posix存在しないと見なされbaseます。(Haskellプラットフォームにありますが、もちろんHackageにもありますので...)
反時計回りに

1
@JanDvorak、私はghciで書き始めます(おそらく変更せずに投稿する必要があります)。しかし、あなたのメモは関係があります、ありがとう。
vlastachu

@leftaroundabout、知りませんでした。基本パッケージを使用していた場合は、できなかったようです。
vlastachu

networkbaseどちらにもないので、独自のソケットバインディングを展開することを除いて、だけでそれを行う実用的な方法はありませんbase
ラムダ妖精

18

PHP

私の知る限り、ほとんどの最新のPHPインストールにはDOM処理が付属しているため、実際には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;
    }
}

内部ループは次のように短縮できます。

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

実際にこれを思いつきました(ここでの最初の答えとして)。あなたが最初にそれをしたので、ここにあなたの+1があります(エラーを起こしやすい正規表現を使用しないため)!ヒント:ラメ使用できる1の代わりをtrueするためにin_array厳格な検索。括弧も省略できます。完全に定かではありませんが、iircをドロップしてhttp、そのまま残すことができます://(スキームを使用しないでください)。。
カイザー

および:別の可能性は、if ( ) {}を支持してドロップすることですin_array() and print $url.PHP_EOL。しかし、ええ、最高の読みやすさのために(もし可能なら)別の+1を得るでしょう:)
kaiser

例を試してみて、厳密な標準(PHP 5.4)でエラーが発生しました。ソースにあるように見えますが、どこかにセミコロンのない破損したリンクや間違った形式のリンクがあります。を使用してエラー報告をオフにすることができます@\DOMDocument。それを試してみて、動作することを確認できます。
カイザー

いや、それは間違ったドキュメントです。技術的には::loadHTMLFile()静的に呼び出すことは想定されておらず、追加する@だけでそのアーティファクトが非表示になります。
ジャック

2
これは間違いなく最も「正しい」ソリューションの1つであり、実稼働環境で使用できる唯一のソリューションの1つです。素敵な仕事
ジョーダンビオンド

14

Unixシェル

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

1行に複数のリンクがある場合、これが機能しないことを認めざるを得ませんが。


1
curl http://www.stroustrup.com/C++.htmlいくつかの文字を保存します。
l0b0

7
「しかし、何のサードパーティのライブラリは許可されません」。私は以来、推測wgetGNU(bashのように)である、あなたはそれがサードパーティではないことを主張することができます。しかし、curl間違いなくサードパーティです。
デジタル外傷

何についてftp://ftp.research.att.com/pub/c++std/WP/CD2https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be
トバイアスキンツラー

4
@TobiasKienzler私はStroustrup氏の元のコードは、どちらかそれらを見つけることができないと思います
ルスラン

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
回答のコードを適切にフォーマットできますか?最も読みにくいコードをめぐって競合するものではありません。少なくとも水平スクロールバーを避けるようにフォーマットできます。
アタリ

を使用するScanner場合、リンクの正規表現パターンを直接処理し、Scannerの結果を反復処理することができます。
ホルガー

5
うん..それはあなたのためのJavaです。それをコードゴルフに使用するのは、勇敢な仕事です。
javadba

4
実際にC ++よりも短いjavaソリューションが表示されるとは思わなかった!
スリーブマン

2
私の最後のコメントの修正:これは、Javaで記述できる最も短くてクリーンなコードであることを認めなければなりません。SAXパーサーアプローチを試しましたが、ラムダを使用するとさらに短くすることができますが、WebページはXHTMLではなく、パーサーは例外をスローします。正規表現が唯一の方法です。
ミスタースミス

11

グルーヴィー

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

?を使用して改善できます。オペレーターはNPEを回避しますか?
クリスK

2
@ChrisKaminskiそして、この辺りでエラーをチェックする最初の人(Bjarneの隣)になりますか?決して!それ以外に、ここではIO関連の例外のみが表示されます。NPEはどこにありますか?
cfrick

findAll()はnullを返す可能性がありますか?または、空のリストを返しますか?Groovyにはまだ少し新しい。編集:nm、findAll()は空のリストを返すように見えます。それらのGroovyの男たちはとても頭がいい。:
クリスK

11

SQL(SQL Anywhere 16)

Webページを取得するストアドプロシージャを定義する

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

単一のクエリを使用して結果セットを生成する

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;

制限:これにより、最大256個のリンクが生成されます。さらにリンクが存在する場合は、256を適切な値に上げます。


2
SQLにゴルフがあるとは思っていませんでした...今まで。
vaxquis

私はそれを得る... "リンク"。:
SAPカナダのジャック、

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
これはCoffeeScript / Nodeですか?私はあなたがそれを指定する必要がありますね...
ジョン・ドヴォルザーク

ワオ。とても読みやすいです。
スリーブマン

@slebetmanそれは確かに小さいですが
ジョンドヴォルザーク

@slebetman Yeah CoffeeScriptはJavaScriptよりもはるかに読みやすいです:)中括弧をすべて
削除できてうれしかったです

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
field-separator変数とrecord-separator変数を避けて、次のようにした場合、コードはより明確になります。print map {"$ _ \ n"} $ response-> content =〜m <"(https?://.+ ?) "> g;
ダニエルルオーソ

@DanielRuosoは同意しました。
プリモ

あるいはuse v5.10;say for $response->content...
マーク・リード

それぞれに、私は思う。バックポートされたperl6の機能のいくつかは問題があります(スマートマッチング、私はあなたを見ています)が、say非常に有用であり、ここで私の頭の中ではより明確です。(また、過去13年間にperl5に完全に無関係なperl6ismの改善がかなりありました。チェックする価値があるかもしれません。)
マークリード

@MarkReed sayこの場合、特にperlに慣れていない人にとっては、おそらくより読みやすいことに同意します。
プリモ

9

R

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

... Rは主にCで書かれていますが...おそらく2行のRコードの後ろに数行のCコードがあります。


2
これ(または類似の何か)は、ほとんどすべての答えに当てはまります。
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
何?Swiftバージョンを書いてください。その角かっこナンセンスは私の目を傷つけています:)
ミスタースミス

2
[]!また、Smalltalkバージョンを完全に追加する必要があります;)
Bersaelor

@MisterSmith Swiftの回答はこちらから入手できます
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]

プット内でhttp :: dataを実行することで逃げることができます。一時変数を作成する必要はありません。そして、改行を入れたり、インデントすることでフォーマットします[。しかし、それはスタイルの選択です。
スリーブマン

7

行く

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このコードはソース全体をメモリに読み込むためregexp.FindReaderIndex、ストリーム内の検索に使用することを検討してください。これにより、アプリが安全になります。


6

CJam

CJamには正規表現がないため、この方法では別のアプローチを使用する必要がありました。

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

最初にすべて'を変換し"、次にすべてに分割し"、すべての代替文字列を取得し、最後にhttp://またはで始まる文字列のリストをフィルタしますhttps://。その後、フィルター処理された各文字列を新しい行に出力します。

次のようなJavaインタープリターを使用して試してください

java -jar cjam-0.6.2.jar file.cjam

file.cjamには上記のコードの内容が含まれています。


9
Cjamは、ウェブの機能を持って知りませんでした...読める部分を知ってはいけない
デフ

あなたはゴルフ、それは...したい場合''/'"f/:+のために''/'"*'"/'"f/0f=
jimmy23013

...ちょっと待ってください'"f/0f=。それは(2%例えば)何かをすることになっていますか?
jimmy23013

6

F#

このコードははるかに短くなる可能性がありますが、多くの不必要な型注釈があるため、このコードを再度読み取りまたは使用する必要があると予想した場合は、このようなものを作成します。アクティブなパターンMatchValueを使用して、標準のCLRタイプのMatchに対するパターンマッチングを有効にする方法を示します。

open System.Net

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

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

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

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

編集 getLinksに独自の関数を作成しました


型注釈の使用方法がとても気に入っています。返されるものを説明するために値に名前を付けることは問題ないと思いますが、関数の名前は十分に表現力があります:getHTMLとhtml値、getLinksとリンクの値。最後の2行はリンクである可能性があります|> Seq.iter(printfn "%s")
MichalMa

@MichalMa関数の名前はそれだけで十分に表現力があり、html変数とlinks変数は実用的な理由で存在することに同意します。したがって、ブレークポイントを設定する場所があります。replではおそらくList.iterを使用していたはずですが、もっと読みやすいという理由だけで、List.iterの代わりにforループを使用しました。
SourceSimian
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.