揭穿Stroustrup揭穿神话“ C ++仅适用于大型,复杂的程序”


161

Stroustrup最近发布了一系列文章,揭露了有关C ++的流行神话。第五个神话是:“ C ++仅适用于大型,复杂的程序”。为了揭穿它,他编写了一个简单的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,重定向等)。因此,沃尔夫拉姆无疑是赢家。在大小和可读性方面非常接近的另一个解决方案是PowerShell(通过注释的改进),但是它并没有引起太多关注。主流语言(PythonC#)也非常接近。


43
对于每个人来说,我都被称为更糟。如果OP的目标不是尝试并以某种方式证明Stroustrup是错误的,那么我同意您的评估。但是问题的整个前提是要显示“您喜欢的语言”如何用更少的代码行就能完成这50行C ++的工作。问题在于这些示例都没有做相同的事情。特别是,没有一个答案执行任何错误检查,没有一个答案提供可重用的功能,大多数答案没有提供完整的程序。Stroustrup示例提供了所有这些。
Dunk 2015年

19
令人遗憾的是,他的网页甚至不是有效的UTF-8。尽管他在服务器上做广告,但现在我必须解决这个问题Content-Type: text/html; charset=UTF-8……我要给他发送电子邮件。
Cornstalks 2015年

27
@Dunk其他示例未提供可重用的功能,因为它们在一行中完成了这些功能的全部功能,因此没有必要单独使用整个功能,并且C ++示例不执行任何错误检查它不是以几乎相同的方式本机处理的,而“完整程序”这一短语几乎毫无意义。
杰森

16
“您可以使用任何语言,但不允许第三方库。” 我不认为这是考虑一个公平的要求boost/asio,使用起来有这一个第三方库。我的意思是不将url / tcp提取作为其标准库的一部分的语言将如何竞争?
greatwolf 2015年

Answers:


115

感觉好像完全作弊

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链接的愚蠢参数。辉煌。
塞斯·巴丁

来到这里提供这个确切的解决方案,很高兴看到其他人也对此表示赞赏。
Michael Stern 2015年

@MartinBüttner在这种情况下,您可能需要考虑投票meta.codegolf.stackexchange.com/a/1078/12130
David Mulder

6
@DavidMulder从技术上讲,当前漏洞是无效的,因为投票细分为+ 41 / -21(漏洞问题指出,如果至少有两倍于向下投票,则可以接受漏洞)。诚然,但仍在密切通话。;)此外,这是一场人气竞赛,而不是一场打高尔夫,尤其是这是一个流行音乐,它展示了如何以给定的语言轻松完成此操作,这就是为什么我认为漏洞并不真正适用于无论如何,这个挑战(因为挑战基本上是要求的)。
Martin Ender 2015年

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 2015年

19
@DevSolar几乎创建了第二个帐户,为您提供了对该评论的另一个赞誉
用户

15
@DevSolar System.Net并不是强制性的,它只是遵循该语言随附的所有.NET建议的高质量库。还有就是替代实现,但其标准库HTTP支持意味着编写简单的应用程序很简单,是指第三方库之间更好的互操作性,意味着更少的依赖,意味着可轻松实现对外墙等想象一个世界没有std::string,试想大家如何使用他们自己的图书馆,想象一下随之而来的所有困难。
Athari 2015年

17
@DevSolar:urllib2不是第三方。就像<iostream>在C ++中一样,它在stdlib 中。与C ++ 不同urllib2,Python中始终可用<boost/asio.hpp>。如果我们被允许使用第三方模块;我会在lxmlBeautifulSoupPython中使用。
jfs 2015年

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

嗯-我想它可能更具可读性...


1
像这样使用管道的unix文件句柄。
javadba

2
哇,没想到没有外部工具就能做到这一点。尽管看来我在LFS上的bash 3.2.17有点过时了,所以它不支持mapfile:)
Ruslan 2015年

@Ruslan Yep,mapfile带有bash4.x 。while read循环也可以完成同一件事。
Digital Trauma 2015年

3
@Ruslan我将其更改为while read而不是mapfile。我认为,它更具便携性和可读性。
Digital Trauma 2015年

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

me脚,但有效


9
为什么不链接很多这样的电话呢?l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
假名称

13
它很短,但不是惯用语(Python中的可读性)
jfs 2015年

24
嗯...如果我所有的代码都忽略了像本例这样的错误,那么我将在每个工作的项目上完成75%到90%的工作。
Dunk 2015年

20
@Dunk:假设该示例确实捕获了一些异常(例如来自urlopen())。除了崩溃和死亡之外,该异常应该怎么办?如果它仍然要崩溃并死亡,为什么不让Python处理崩溃和死亡,而完全放弃异常处理呢?
凯文

8
@Dunk:如果我使用的是其他人的Python代码,我宁愿它们捕获urlopen错误而不是(例如)捕获错误并调用sys.exit("something's borked!")。如果他们做后者,我必须抓住SystemExit,这从来没有乐趣。
凯文(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
您可以使用var html,并且var match可以删除一些字符。
极好的

15
@好极了,我可以使名称成为单字符并html完全摆脱变量,但这不是我想要的。
Athari'1

6
@Superbest不是代码高尔夫球。:D
Kroltan 2015年

5
好吧,它也提高了可读性。var当它不会影响代码语义时,有没有理由不使用它?
极好的

6
@Superbest:“它提高了可读性”是主观的。我个人认为,明确声明变量的类型可以提高可读性(通常,如此处的代码所示)。不过,我不想对此争论。我只想指出,存在其他观点。
Cornstalks 2015年

54

“没有第三方”是谬论

我认为“没有第三方”的假设是谬论。这是困扰C ++开发人员的一个特殊谬论,因为很难在C ++中创建可重用的代码。当您完全开发任何内容时,即使它只是一个小脚本,您也将始终利用任何可用的可重用代码段。

问题是,在诸如Perl,Python,Ruby(仅举几例)之类的语言中,重用别人的代码不仅容易,而且大多数人在大多数时间实际上是在编写代码。

C ++几乎无法维护兼容的ABI要求,这使这项工作变得更加艰巨,最终您会遇到一个像Boost这样的项目,该项目是一个庞大的代码存储库,而且外部几乎没有可组合性。

CPAN示例

只是为了好玩,这里有一个基于CPAN的示例,它对html进行了正确的解析,而不是尝试使用正则表达式来解析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
给予好评解决第三方库的点,而是:废话,使得可重用的代码在C ++是在其他语言一样容易俗气。使用,尤其是寻找可重用的代码可能会有点困难,但是这是严重的问题是重复使用的唯一的事情编译文物,但是这往往是一个非问题在像Perl等解释语言
马丁巴

4
打个比方,Boost更像CPAN-选择。您不会将CPAN称为“庞大的代码存储库”,只是因为其中有很多您不使用的东西?
马丁·巴

22
根据这四个词的任何合理定义,CPAN 一个“庞大的代码存储库”。
jwg 2015年

3
@MartinBa我不同意,C ++是一种编译语言,要求每个可执行文件都重建其完整的依赖关系堆栈,因为很难维持ABI兼容性会严重阻碍代码的可重用性。为了用C ++生成可重用的库,您必须经过很长的时间,以确保您不会一直强迫自己进行与ABI不兼容的更改。
Daniel Ruoso 2015年

6
@MartinBa,因为每次想要实现一个简单任务时都必须重建整个宇宙,这简直难以忍受。
Daniel Ruoso 2015年

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
我无法确定是+1是因为使用Web浏览器下载网页是该工作的正确工具,还是-1是因为面临的挑战是编写一个程序来执行该操作,而您只是调用了一个程序来执行该操作炽热。
David Richerby,2015年

2
我认为最好用curl或wget代替山猫。它们更常用于下载网页。
Pavel Strakhov 2015年

4
@PavelStrakhov我选择了lynx正是因为它可以不用我做任何特别的事情就可以丢弃链接:)
Ruslan

2
@SteveJessop通过“特殊”,我的意思是实际上解析或正则表达式或其他。使用lynx,我只需grep出链接列表(curl和wget不会列出)并删除编号。您可能会认为它是作弊之类,但我认为{使用几乎可以完美完成所需功能的工具} 很有趣,只需微调输出即可。
Ruslan 2015年

7
“但是不允许第三方库”。我认为lynx这种情况下在功能上等同于第三方库。
Digital Trauma 2015年

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

1
这是美丽的,完全令人恐惧。+1
ricdesi

36

Clojure

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

27
lur?我需要学习Clojure。
5684年

10
@ 11684 - Clojure的还有一个名为标准功能spitzipper以及lazy-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
考虑到此代码的紧凑性和可读性,我有点失望,因为它没有更多的票数。做得好。
Spacemoose

28

斯卡拉

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

8
将所有内容打包在一行中-C ++也可以做到这一点
quetzalcoatl

ftp://ftp.research.att.com/pub/c++std/WP/CD2
Tobias Kienzler 2015年

22
@quetzalcoatl-这是一个表达式,而不仅仅是一行。您可以删除C ++代码中的所有换行符,但这与在单个表达式中完成整个任务不同。
道文

4
@DaoWen:对不起,但是开始使用expressions-vs-line太愚蠢了。添加一些函子和C ++,您也可以做到。但这只是什么库被认为“已授予”和“内部包含零代码”的问题。将其打包成一行不影响可读性这一事实并没有改变。可以将其作为单个表达式保持不变,只需将其重新格式化为几行即可获得更多收益,而..行数则无所作为。这就是我的意思。愚蠢的打包-C ++也可以做到。如果有人想摆脱“愚蠢的包装”框,那么应该格式化代码以提高可读性,而不是行数。
quetzalcoatl 2015年

3
@quetzalcoatl托比亚斯(Tobias)并未在其中放置链接,以供我们关注。他在问这个答案的作者为什么它不在他的结果中。
JLRishe 2015年

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]);(仅输出网址)。
primo 2015年

已修复,谢谢您的输入
David Xu

@DavidXu除了您没有解决它...?
Shahar 2015年

现在固定了!
David Xu

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 +)的别名。
Athari'1

8
您可能会滥用PowerShell拼合集合的渴望,并这样做:((iwr "http://www.stroustrup.com/C++.html").Links.href(iwr "http://www.stroustrup.com/C++.html").Links.href-match":"仅用于绝对URI)
Mathias R. Jessen

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 2015年

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语句并缩短另一行。
Unihedron

@Unihedro确实如此。
TimWolla 2015年

9
@Unihedro可以,但这不是高尔夫比赛。
cPu1 2015年

您不需要使用任何捕获组。
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')来缩短请求(并保持其可读性)。所以整个代码可以在一行中(保持它的可读性)puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"})。运行它,ruby -rnet/http甚至不需要require 'net/http'行。
Hauleth 2015年

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明确指定类型?应该在.NET中使用它来完全限制它unlines
John Dvorak 2015年

1
这样做确实会使规则有所扩展,因为它们既不在包中,Network.HTTP也不TextRegex.Posixbase包中。(尽管它们位于Haskell平台中,并且当然也包含在Hackage中,所以...)
不再是

1
@JanDvorak,我开始用ghci编写(可能我应该将其保持不变)。但是,您的留言很有意义,谢谢。
vlastachu 2015年

@leftaroundabout,不知道。如果使用了基本软件包,看来我做不到。
vlastachu 2015年

networkbase两者都不存在,因此除了滚动自己的套接字绑定之外,没有实际的方法使用just来实现base
Lambda Fairy

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(因为不使用容易出错的Regex)!提示:你可以使用一个跛脚1的,而不是truein_array严格的搜索。您也可以省略括号。我不太确定,但是iirc您也可以删除,http而只留下://(不使用方案)。。
kaiser 2015年

并且:另一种可能性是放弃if ( ) {}支持in_array() and print $url.PHP_EOL。但是,是的,您将再获得+1(如果可以的话),以实现最佳可读性:)
kaiser 2015年

刚尝试了您的示例,并遇到了严格标准(PHP 5.4)的错误。好像在源中一样,某个地方的链接已损坏或格式错误,缺少分号。您可以使用来关闭错误报告@\DOMDocument。刚刚尝试过,可以确认它是否有效。
kaiser 2015年

不,那是文档错误。从技术上讲,您不应::loadHTMLFile()静态调用,而@只能添加该伪像的皮革。
2015年

2
这绝对是最“正确”的解决方案之一,这是我在生产中使用的仅有的解决方案之一。干得好
Jordon Biondo

14

Unix Shell

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

虽然我必须承认,如果一条线上有多个链接,这是行不通的。


1
curl http://www.stroustrup.com/C++.html保存几个字符。
l0b0 2015年

7
“但是不允许第三方库”。我猜因为wget是GNU(与bash一样),所以您可以说它不是第三方。但是curl绝对是第三方。
Digital Trauma 2015年

怎么样ftp://ftp.research.att.com/pub/c++std/WP/CD2https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be
Tobias Kienzler 2015年

4
@TobiasKienzler我想Stroustrup的原始代码也找不到它们
Ruslan

14

爪哇

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
您可以在答案中正确格式化代码吗?可读性最低的代码不是竞争。您可以设置其格式以避免至少水平滚动条。
Athari 2015年

如果您使用a Scanner,则可以使其直接处理链接的regex模式并遍历Scanner的结果。
Holger 2015年

5
是的..那是适合您的java。将其用于代码高尔夫球是一项勇敢的工作。
javadba

4
没想到我会看到实际上比C ++短的Java解决方案!
slebetman'1

2
更正我的最后一条评论:我必须承认这几乎是可以用Java编写的最短,最简洁的代码。我尝试了SAX解析器方法,使用lambda可以使它更短,但是网页不是XHTML,并且解析器会引发异常。正则表达式是唯一的方法。
史密斯先生

11

Groovy

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

定义存储过程以获取网页

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 2015年

我明白了...“链接”。:-)
Jack在加拿大加拿大(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
我猜这是CoffeeScript / Node?我猜您应该指定...
John Dvorak 2015年

哇。这很可读。
slebetman 2015年

@slebetman绝对是很小,但
约翰·德沃夏克

@slebetman是的,CoffeeScript比JavaScript更具可读性:)我很高兴摆脱了所有花括号} :)
RobAu

9

佩尔

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
如果您避免使用字段分隔符和记录分隔符变量,而只是这样做,则代码将更加清晰:print map {“ $ _ \ n”} $ response-> content =〜m <“(https?://.+ ?)“> g;
Daniel Ruoso 2015年

@DanielRuoso同意。
2015年

甚至use v5.10;say for $response->content...
马克·里德

我想对每个人来说。向后移植的perl6功能有些问题(智能匹配,我在看你),但say功能非常有用,在我看来,这很清楚。(此外,在过去13年中,对perl5进行了很多与perl6ism完全无关的改进;可能值得一试。)
Mark Reed

@MarkReed我同意say这种情况下的可读性更好,特别是对于那些不太熟悉perl的人。
2015年

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 2015年

8

目标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的答案现在可以在这里找到
2016年

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来摆脱困境。无需创建临时变量。而且我还会通过换行并缩进来格式化它[。但这是一种风格选择。
slebetman'1

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没有正则表达式,因此我不得不在此方法中使用另一种方法:

"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具有网络功能
Def的

如果你想打高尔夫球吧... ''/'"f/:+''/'"*'"/'"f/0f=
jimmy23013 2015年

...等等为什么在'"f/0f=那里?那应该做某事吗(2%例如)?
jimmy23013 2015年

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和链接值。最后两行可能是链接|> Seq.iter(printfn“%s”)
MichalMa 2015年

@MichalMa我同意函数的名称本身具有足够的表现力,出于实用的原因,存在html和links变量:因此可以在某处设置断点。我使用for循环而不是List.iter只是因为我喜欢它的读取方式,尽管在一个repl中我可能会使用List.iter。
SourceSimian 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.