# Debunking Stroustrup's debunking of the myth “C++ is for large, complicated, programs only” [closed]

Stroustrup has recently posted a series of posts debunking popular myths about C++. The fifth myth is: “C++ is for large, complicated, programs only”. To debunk it, he wrote a simple C++ program downloading a web page and extracting links from it. Here it is:

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


Let's show Stroustrup what small and readable program actually is.

1. Download http://www.stroustrup.com/C++.html

2. List all links:

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


You can use any language, but no third-party libraries are allowed.

# Winner

C++ answer won by votes, but it relies on a semi-third-party library (which is disallowed by rules), and, along with another close competitor Bash, relies on a hacked together HTTP client (it won't work with HTTPS, gzip, redirects etc.). So Wolfram is a clear winner. Another solution which comes close in terms of size and readability is PowerShell (with improvement from comments), but it hasn't received much attention. Mainstream languages (Python, C#) came pretty close too.

# Comment on subjectivity

The most upvoted answer (C++) at the moment votes were counted was disqualified for not following the rules listed here in the question. There's nothing subjective about it. The second most upvoted question at that moment (Wolfram) was declared winner. The third answer's (Bash) "disqualification" is subjective, but it's irrelevant as the answer didn't win by votes at any point in time. You can consider it a comment if you like. Furthermore, right now the Wolfram answer is the most upvoted answer, the accepted one, and is declared winner, which means there's zero debate or subjectivity.

• To each his own, I've been called worse. If the OP's goal wasn't to try and somehow prove that Stroustrup is wrong, then I'd agree with your assessment. But the entire premise of the question is to show how "your favorite language" can do the same thing as this 50 lines of C++ in much less lines of code. The problem is that none of the examples do the same thing. In particular, none of the answers perform any error checking, none of the answers provide reusable functions, most of the answers don't provide a complete program. The Stroustrup example provides all of that.
– Dunk
Jan 8 '15 at 15:40
• What's sad is his web page isn't even valid UTF-8. Now I've gotta work around that, despite his server advertising Content-Type: text/html; charset=UTF-8... I'm gonna email him. Jan 8 '15 at 16:33
• @Dunk The other examples don't provide reusable functions because they accomplish the entire functionality of those functions in a single line and it makes no sense to make that a whole function on its own, and the C++ example doesn't perform any error checking that isn't handled natively in almost an identical manner, and the phrase "complete program" is almost meaningless. Jan 8 '15 at 21:09
• "You can use any language, but no third-party libraries are allowed." I don't think that's a fair requirement considering boost/asio is used up there which is a third-party library. I mean how will languages that don't include url/tcp fetching as part of its standard library compete? Jan 9 '15 at 6:43
• He's... parsing... html... with... regex... twitch
– Riot
Jan 15 '15 at 5:53

# Wolfram

This feels like complete cheating

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


So just add some honest parsing on top

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

• Nope, I don't see any cheating here. This challenge is about bringing out the best of your language. And that first line is the epitome of "small and readable". Jan 7 '15 at 19:01
• An answer that can ignore the silly arguments about catching ftp links. Brilliant. Jan 8 '15 at 17:11
• Came here to offer this exact solution, pleased to see others have appreciated it as well. Jan 11 '15 at 15:28
• @MartinBüttner In that case you might want to consider downvoting meta.codegolf.stackexchange.com/a/1078/12130 Jan 12 '15 at 15:56
• @DavidMulder Technically, the loophole is currently not valid, since the vote breakdown is +41/-21 (and the loophole question states that loopholes are accepted if there are at least twice as many upvotes as downvotes). A close call, admittedly, but still. ;) Furthermore, this is a popularity contest, not a code golf, and in particular, it's a pop-con about showing how easily this can be done in a given language, which is why I think the loophole doesn't really apply to this challenge anyway (since the challenge basically asks for it). Jan 12 '15 at 16:06

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


The main shortcoming is the awkward nature of boost::asio, I'm sure it can be even shorter with a better library.

• I think using boost is fair, since large parts of it have been integrated into the standard library in the past, and there have been plans to integrate asio in a future version.
– usm
Jan 8 '15 at 9:40
• What about ftp://ftp.research.att.com/pub/c++std/WP/CD2 and https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be? Jan 8 '15 at 12:20
• using std::string; would somewhat simplify the code (and will make the long line short enough so as not to require the horizontal scrolling bar). Jan 9 '15 at 11:24
• @DevSolar You can consider boost a part of the standard library for C++ if you wish, it's a staging area for the standard library anyway. However, even with boost, you still have to know inner workings of HTTP protocol. It may look simple in this sample, but imagine you need to support HTTPS, gzip, redirects etc. Will it be as simple? Bare TCP socket quickly becomes insufficient. Jan 9 '15 at 16:09
• you don't need Host header in HTTP/1.0
– jfs
Jan 11 '15 at 9:36

# Pure Bash on Linux/OS X (no external utilities)

HTTP client software is notoriously bloated. We don't want those kinds of dependencies. Instead we can push the appropriate headers down a TCP stream and read the result. No need to call archaic utilities like grep or sed to parse the result.

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 - I suppose it could be more readable... • Like this one using unix file handles for the pipes. Jan 8 '15 at 1:52 • Wow, never thought one can do this without external utils. Although it seems my bash 3.2.17 on LFS is a tiny bit obsolete so that doesn't support mapfile :) Jan 8 '15 at 7:01 • @Ruslan Yep, mapfile comes with bash 4.x. The same thing is totally doable with a while read loop as well. Jan 8 '15 at 17:06 • @Ruslan I changed it to while read instead of mapfile. More portable and more readable, I think. Jan 8 '15 at 17:37 • Works on OS X, too! Jan 11 '15 at 21:23 # 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, but works • Why not chain a lot of those calls? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read()) Jan 7 '15 at 9:57 • It is short but it is not idiomatic (readability counts in Python) – jfs Jan 7 '15 at 12:50 • Hmmm...if all my code ignored errors like this example then 75% to 90% of my work would already be done on every project I work on. – Dunk Jan 7 '15 at 15:37 • @Dunk: Suppose the example did catch some exception (e.g. from urlopen()). What should it do with such an exception, other than crash and die? If it's going to crash and die anyway, why not just let Python handle the crashing-and-dying, and leave off the exception handling altogether? Jan 8 '15 at 19:51 • @Dunk: If I were using somebody else's Python code, I'd much rather they not catch urlopen errors than (say) catch them and call sys.exit("something's borked!"). If they do the latter, I have to catch SystemExit, which is never fun. Jan 8 '15 at 21:13 # C# using System; using System.Net; using System.Text.RegularExpressions; string html = new WebClient().DownloadString("http://www.stroustrup.com/C++.html"); foreach (Match match in Regex.Matches(html, @"https?://[^""]+")) Console.WriteLine(match);  • You can use var html, and probably var match to shave off a few characters. Jan 7 '15 at 20:43 • @Superbest I can make names single-character and get rid of html variable altogether too, but it's not what I'm after. Jan 7 '15 at 22:36 • @Superbest not code-golf. :D Jan 7 '15 at 23:26 • Well, it improves readability, too. Is there ever a reason not to use var when it won't impact code semantics? Jan 8 '15 at 20:56 • @Superbest: "it improves readability" is subjective. Personally, I think explicitly stating the type of the variable improves readability (usually, like in this code here). I don't want to debate this, though; I just want to point out that alternative views exist. Jan 8 '15 at 23:55 # "No third-party" is a fallacy I think the "no third-party" assumption is a fallacy. And is a specific fallacy that afflicts C++ developers, since it's so hard to make reusable code in C++. When you are developing anything at all, even if it's a small script, you will always make use of whatever pieces of reusable code are available to you. The thing is, in languages like Perl, Python, Ruby (to name a few), reusing someone else's code is not only easy, but it is how most people actually write code most of the time. C++, with its nearly impossible-to-maintain-compatible-ABI-requirements makes that a much tougher job, you end up with a project like Boost, which is a monstrous repository of code and very little composability outside it. ## A CPAN example Just for the fun of it, here goes a CPAN-based example, with proper parsing of the html, instead of trying to use regex to parse 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");

• Upvote for addressing the point of the 3rd party libs, but: crap, making reusable code in C++ is as easy cheesy as in other language. Using and especially finding reusable code may be a tad harder, but the only thing that's seriously problematic is reusing compiled artifacts, but that's often a non-issue in interpreted languages like Perl, etc. Jan 8 '15 at 9:47
• To stretch an analogy, Boost is more like CPAN - pick and choose. You don't call CPAN a "monstrous repository of code" just because there's such a lot of stuff in there you don't use? Jan 8 '15 at 9:49
• CPAN is a 'monstrous repository of code', by any reasonable definition of those four words.
– jwg
Jan 8 '15 at 14:39
• @MartinBa I disagree, C++ being a compiled language, requiring every executable to rebuild its full stack of dependencies because it's hard to maintain ABI compatibility seriously hinders code reusability. In order to produce a reusable library in C++ you have to go through really long lengths in order to make sure you don't force yourself into ABI-incompatible changes all the time. Jan 8 '15 at 16:53
• @MartinBa because having to rebuild the whole universe everytime you want to implement a simple task is unbearable. Jan 8 '15 at 20:59

# UNIX shell

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


Also finds an ftp:// link :)

Another way, without relying on :// syntax:

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

• I can't work out whether to +1 because using a web browser to download a web page is the right tool for the job or to -1 because the challenge is to write a program to do blahblahblah and you just called a program to do the blahing. Jan 7 '15 at 11:44
• I think it's better to replace lynx with curl or wget. They are more commonly used to download a webpage. Jan 7 '15 at 14:03
• @PavelStrakhov I chose lynx exactly because it can dump the links without me doing anything special :) Jan 7 '15 at 14:06
• @SteveJessop by "special" I mean actually parsing or regexing or whatever. With lynx I just grep out the list of links (which curl and wget don't list) and remove the numbering. You may consider it cheating or whatever, but I thought it's fun to {use the tool which almost perfectly does what is required}, just fine-tuning the output. Jan 7 '15 at 15:37
• "but no third-party libraries are allowed". I contend that lynx is functionally equivalent to a third-party library in this scenario. Jan 7 '15 at 20:32

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


This code can be used as a user style to display only absolute links on a page in an unformatted list. It may not work correctly if your browser enforces minimum font size.

It works correctly with http://www.stroustrup.com/C++.html (note !important on background). In order to work on other pages with more styles, it must be extended (reset more properties, mark properties as important etc.).

Alternative version which includes relative links except intrapage links starting with hashes (it relies on a hard-coded absolute link, unfortunately):

* {
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);
}

• This is the worst thing I've ever seen. +1 Jan 13 '15 at 18:11
• This is beautiful and completely horrifying. +1 Jun 1 '16 at 15:59

# Clojure

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

• Slurp?! I need to learn Clojure. Jan 8 '15 at 10:01
• @11684 - Clojure also has standard functions named spit, zipper, and lazy-cat... :-) Jan 9 '15 at 19:13
• Wow, I think that's gonna be a late New Year's Resolution. @BobJarvis Jan 9 '15 at 21:36

## Emacs Lisp

(with-current-buffer (url-retrieve-synchronously "http://www.stroustrup.com/C++.html")
(while (re-search-forward "https?://[^\\\"]*")
(print (match-string 0))))

• I'm a little dissapointed, given how compact and eminently readable this code is, that it does not have more votes. Well done. Jan 16 '15 at 11:40

Scala

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

• pack everything in one line - C++ can do it too Jan 8 '15 at 9:57
• What about ftp://ftp.research.att.com/pub/c++std/WP/CD2? Jan 8 '15 at 12:19
• @quetzalcoatl - This is one expression, not just one line. You can just delete all of the line breaks from the C++ code, but that's not the same thing as doing the whole task in a single expression. Jan 8 '15 at 23:56
• @DaoWen: Sorry, but starting expressions-vs-line is just going silly. Add some functors and C++ you can do it too. But that's just the question of what libs are considered to be "granted" and have "zero code inside". It doesn't change the fact that packing it into a line hurst readability. One can keep it still as a single expression and just reformat it into a few lines to gain much and loose nothing other than .. line count. That's my point. Silly packing - C++ can do it too. If someone wants to get out of the "silly packing" box, then should format the code for readability, not linecount. Jan 9 '15 at 11:27
• @quetzalcoatl Tobias didn't put the link there for us to follow it. He was asking the writer of this answer why it wasn't in his results. Jan 9 '15 at 21:19

# PHP 5

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

• Suggested edits: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|' (currently an error); remove array_unshift($m); (currently an error, you likely meant array_shift instead); print_r($m);print_r($m[1]); (only output the urls). Jan 7 '15 at 10:12 • fixed, thanks for your input Jan 7 '15 at 17:13 • @DavidXu Except you didn't fix it...? Jan 7 '15 at 18:00 • now its fixed.! Jan 7 '15 at 19:17 ## PowerShell Text search for all fully-qualified URLs (including JavaScript, CSS, etc.): [string[]][regex]::Matches((iwr "http://www.stroustrup.com/C++.html"), '\w+://[^"]+')  Or to get links in anchor tags only (includes relative URLs): (iwr "http://www.stroustrup.com/C++.html").Links | %{$_.href }


Shorter versions from comments:

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

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

• If anyone wonders, iwr is an alias for Invoke-WebRequest (PS3+). Jan 7 '15 at 23:59
• You could abuse PowerShell's eagerness to flatten collections and do: (iwr "http://www.stroustrup.com/C++.html").Links.href (or (iwr "http://www.stroustrup.com/C++.html").Links.href-match":" for only absolute URI's) Jan 8 '15 at 22:11
• That's pretty handy! Jan 9 '15 at 6:20

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

• To make the list similar to the original example, you could pipe the program's output through | sort | uniq or instead add import std.array and change the line .filter!("a")){ writeln(_.front[1]); } into this: .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Note, however, that I have only tried this code and not proved it to be correct or "idiomatic". :)
– Frg
Jan 10 '15 at 11:58

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

• I wonder if require('http').get works. If it does then we can ditch the var statement and shorten another line. Jan 7 '15 at 17:46
• @Unihedro It does. Jan 7 '15 at 18:22
• @Unihedro It does, but this isn't a golfing contest. Jan 7 '15 at 19:43
• You don’t need to use any capturing groups.
– Ry-
Jan 15 '15 at 0:25
• I think it's JavaScript rather than a framework name.
– mr5
Jan 17 '15 at 16:09

# Haskell

Some troubles with "\w" in 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

• Why is the type of result specified explicitly? It should be fully constrained by its use in unlines. Jan 7 '15 at 16:25
• This does stretch the rules a bit, seeing as neither Network.HTTP nor TextRegex.Posix are in the base package. (Though they are in the Haskell Platform, and of course on Hackage, so...) Jan 7 '15 at 20:49
• @JanDvorak, I start to write in ghci (probably i should post it unchanged). But your note is relevant, thanks. Jan 9 '15 at 12:22
• @leftaroundabout, did not know. It looks like I could not have done, if had used the base package. Jan 9 '15 at 12:35
• network isn't in base either, so save for rolling your own socket bindings there's no practical way to do it with just base. Jan 13 '15 at 10:09

# Ruby

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

• Your regex will fail, you need to use %r{"(https?://[^"]+)"}. Also you can use Net::HTTP.get('www.stroustrup.com', '/C++.html') to shorten up request (and keep it readable). So whole code can be in one line (keeping it readable): puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Run it with ruby -rnet/http and you don't even need require 'net/http' line. Jan 12 '15 at 22:47

# PHP

As far as I can tell, most modern PHP installations come with DOM processing, so here's one that actually traverses the anchors inside the 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;
}
}


The inner loop could be shortened to:

preg_match('~^https?://~', $url =$a->getAttribute('href')) && printf("%s\n", $url);  • Actually wanted to come up w this (as my first answer here). You did it first, so here's your +1 (for not using an error prone Regex)! Hint: You could use a lame 1 instead of the true for the in_array strict search. You can as well omit the brackets. I'm not completely sure, but iirc you could as well drop the http and only leave the :// (go w/o the scheme). . Jan 10 '15 at 12:27 • And: Another possibility would be to drop the if ( ) {} in favor of in_array() and print$url.PHP_EOL. But yeah, you would get another +1 (if I could) for best readability :) Jan 10 '15 at 12:30
• Just tried your example and got an error for strict standards (PHP 5.4). Seems like in the source, there's somewhere a corrupted or wrongly formatted link with a missing semicolon. You could turn off error reporting by using @\DOMDocument. Just tried that and can confirm it works. Jan 10 '15 at 14:10
• Nah, it's the documentation that's wrong; technically you're not supposed to call ::loadHTMLFile() statically, and adding @ only hides that artefact.
– Jack
Jan 10 '15 at 14:12
• This is definitely one of the most "correct" solutions, one of the only ones I could see in use in production. nice job Jan 13 '15 at 14:29

# Unix Shell

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


Though i have to admit this doesn't work if there's more than one link on a line.

• curl http://www.stroustrup.com/C++.html saves a few characters.
– l0b0
Jan 7 '15 at 14:56
• "but no third-party libraries are allowed". I guess since wget is GNU (as is bash), you could argue that it is not third-party. But curl definitely is third-party. Jan 7 '15 at 20:34
• What about ftp://ftp.research.att.com/pub/c++std/WP/CD2 and https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be? Jan 8 '15 at 12:21
• @TobiasKienzler I guess Stroustrup's original code doesn't find them either Jan 8 '15 at 17:05

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

• Could you properly format code in your answers? It isn't competition for the least readable code. You can format it to avoid horizontal scrollbars at least. Jan 7 '15 at 9:07
• If you use a Scanner you can make it processing the regex pattern for links directly and iterate over the Scanner’s results. Jan 7 '15 at 9:11
• Yep .. that's java for you. Using it for code golf is a brave undertaking. Jan 8 '15 at 1:53
• Never thought I'd see a java solution that's actually shorter than C++! Jan 8 '15 at 2:59
• Correction to my last comment: I must admit this is pretty much the shortest and cleanest code that can be written in Java. I've tried a SAX parser approach, which could be made even shorter with lambdas, but the web page is not XHTML and the parser throws exceptions. Regex is the only way to go. Jan 9 '15 at 15:59

# Groovy

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

• Could be improved by using ?. operator to avoid NPEs? Jan 8 '15 at 14:31
• @ChrisKaminski and be the first (beside Bjarne) around here to check for errors? never! beside that: i only see IO related exceptions here. where do you see a NPE? Jan 8 '15 at 14:53
• findAll() could return null, no? Or will it return an empty list? Still a bit new to Groovy. EDIT: nm, looks like findAll() returns an empty list. Those Groovy guys were so smart. :-) Jan 8 '15 at 15:11

# SQL (SQL Anywhere 16)

## Define a stored procedure to fetch the web page

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


## Produce the result set using a single query

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;


Limitations: This produces up to 256 links. If more links exist, then bump up the 256 to an appropriate value.

• I didn't believe there would be golf in SQL... until now.
– user18967
Jan 11 '15 at 12:05
• I get it ... "links". :-) Jan 15 '15 at 15:31

# 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


• I guess this is CoffeeScript/Node? I guess you should specify that... Jan 7 '15 at 16:27
• Wow. That's very readable. Jan 8 '15 at 3:00
• @slebetman it definitely is small though Jan 8 '15 at 7:06
• @slebetman Yeah CoffeeScript is so much more readable than JavaScript :) I was glad to get rid of all the curly braces }:) Jan 8 '15 at 7:54

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

• The code would be more clear if you avoided the field-separator and record-separator variables and just did: print map { "$_\n" }$response->content =~ m<"(https?://.+?)">g; Jan 7 '15 at 16:55
• @DanielRuoso agreed. Jan 8 '15 at 6:50
• or even use v5.10; and say for $response->content... Jan 8 '15 at 18:41 • To each his own, I suppose. Some of the backported perl6 features have been problematic (smart matching, I'm looking at you), but say is quite useful, and in my mind clearer here. (Also, there have been rather a lot of completely-unrelated-to-perl6ism improvements to perl5 in the last 13 years; it might be worth checking out.) Jan 8 '15 at 20:15 • @MarkReed I agree that say is probably more readable in this case, particularly for those less familiar with perl. Jan 10 '15 at 5:26 # R html<-paste(readLines("http://www.stroustrup.com/C++.html"),collapse="\n") regmatches(html,gregexpr("http[^([:blank:]|\\\"|<|&|#\n\r)]+",html))  ...although R is written mainly in C... so probably a few lines of C code behind those 2 lines of R code. • That (or something similar) is true for pretty much all the answers here. Jan 8 '15 at 18:39 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]]); }  • What? Please write the Swift version. That square bracket nonsense is hurting my eyes :) Jan 8 '15 at 21:09 • Hurray for []! Also, we should totally add a Smalltalk version ;) Jan 9 '15 at 9:52 • @MisterSmith Swift answer now available here. – JAL Jun 1 '16 at 21:23 ## 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]

• You can get away by doing http::data inside the puts. No need to create a temporary variable. And I'd also format it by putting newlines and indenting at every [. But that's a style choice. Jan 8 '15 at 2:58

# Go

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


P.S. this code reads entire source into memory, so consider using regexp.FindReaderIndex to search in stream, that'll make the app bulletproof.

# CJam

CJam does not have regex so I had to use a different approach in this one:

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


I first convert all ' to ", then I split on all ", take every alternative string and then finally filter that list for strings starting with http:// or https://. After that, simply print each filtered string on a new line.

Try it using the Java interpreter like

java -jar cjam-0.6.2.jar file.cjam


where file.cjam has the contents of the code above.

• Don't know about the readable part... didn't know Cjam has web functionality
– Def
Jan 7 '15 at 12:16
• If you want to golf it... ''/'"f/:+ for ''/'"*'"/'"f/0f=. Jan 7 '15 at 14:08
• ...wait why is '"f/0f= there? Is that supposed to do something (2% for instance)? Jan 7 '15 at 14:14

# F#

This code could be far shorter but I would write something like this if I ever expected to have to read or use this code again so it has many unnecessary type annotations. It demonstrates the use of an active pattern MatchValue to enable pattern-matching against the standard CLR type 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 I made getLinks its own function

• I really like how you used type annotations. I think naming values to describe what you return is ok, but name of the function is expressive enough: getHTML and html value, getLinks and links value. Last two lines may be links |> Seq.iter (printfn "%s") Jan 11 '15 at 10:36
• @MichalMa I agree that the name of the function is expressive enough on its own, the html and links variables are there for pragmatic reasons: so there is somewhere to set a breakpoint. I used the for loop instead of List.iter just because I like the way it reads more, although in a repl I probably would have used List.iter. Jan 12 '15 at 4:13