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, 리디렉션 등). 따라서 Wolfram 은 확실한 승자입니다. 크기와 가독성 측면에서 가까운 또 다른 솔루션은 PowerShell (설명을 개선 한 것)이지만 많은 관심을받지 못했습니다. 주류 언어 ( Python , C # )도 매우 가까워졌습니다.


43
자신의 입장에서 나는 더 나 빠졌다. OP의 목표가 시도하지 않았고 Stroustrup이 잘못되었다는 것을 어떻게 입증했는지에 대해서는 귀하의 평가에 동의합니다. 그러나이 질문의 전제는 "좋아하는 언어"가 훨씬 적은 수의 코드 줄에서이 50 줄의 C ++과 동일한 기능을 수행 할 수있는 방법을 보여주는 것입니다. 문제는 예제 중 어느 것도 같은 일을하지 않는다는 것입니다. 특히, 어떤 대답도 오류 점검을 수행하지 않으며, 어떤 대답도 재사용 가능한 기능을 제공하지 않으며, 대부분의 대답은 완전한 프로그램을 제공하지 않습니다. Stroustrup 예제는이 모든 것을 제공합니다.
Dunk

19
슬픈 것은 그의 웹 페이지가 심지어 UTF-8조차도 유효하지 않다는 것 입니다. 이제 그의 서버 광고에도 불구하고 그 문제를 해결해야합니다 Content-Type: text/html; charset=UTF-8... 나는 그를 이메일로 보낼 것입니다.
Cornstalks

27
@Dunk 다른 예제는 재사용 가능한 함수를 제공하지 않습니다. 함수의 전체 기능을 한 줄로 수행하기 때문에 전체 함수를 자체적으로 만드는 것은 의미가 없으며 C ++ 예제에서는 오류 검사를 수행하지 않습니다. 기본적으로 거의 동일한 방식으로 처리되지 않으며 "완전한 프로그램"이라는 문구는 거의 의미가 없습니다.
Jason

16
"모든 언어를 사용할 수 있지만 타사 라이브러리는 허용되지 않습니다." 나는 고려 정당한 요구라고 생각하지 않는 boost/asio한 거기 사용되는 것입니다 타사 라이브러리. 표준 라이브러리의 일부로 url / tcp 가져 오기를 포함하지 않는 언어는 어떻게 경쟁합니까?
greatwolf

답변:


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
아니, 여기 속임수가 보이지 않습니다. 이 도전은 당신의 언어를 최대한 활용하는 것입니다. 그리고 첫 번째 줄은 "작고 읽기 쉬운"의 전형입니다.
Martin Ender

ftp 링크를 잡는 것에 대한 바보 같은 주장을 무시할 수있는 대답. 훌륭한.
Seth Battin

이 정확한 솔루션을 제공하기 위해 여기에 왔으며 다른 사람들 도이 솔루션을 높이 평가했습니다.
Michael Stern

@ MartinBüttner이 경우 meta.codegolf.stackexchange.com/a/1078/12130 downvoting
David Mulder

6
@DavidMulder 기술적으로, 투표율이 + 41 / -21이므로 허점은 현재 유효하지 않습니다 (그리고 허점 질문은 허점은 다운 보트보다 최소한 두 배의 찬성표가있는 경우 허점이 허용됨을 나타냅니다). 물론 가까운 전화. ;) 또한 이것은 코드 골프가 아닌 인기 경연 대회이며, 특히 주어진 언어로 얼마나 쉽게 수행 할 수 있는지 보여주는 팝콘입니다. 그래서 허점은 실제로 적용되지 않는다고 생각합니다. 어쨌든이 도전은 도전이 기본적으로 그것을 요구하기 때문에.
마틴 엔더

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
"타사 라이브러리가 없음"이 파이썬이 여전히 import urllib2, C3이 여전히 using System.Net, 하스켈이 여전히을 의미하는 방법에 대해 재미있는 점 은 import Network.HTTP있지만 C ++ 코더는 #include <boost/asio.hpp>특수 목적의 특수 목적으로 구축 된 C ++ (및 C!) 라이브러리의 측정 기준을 갖는 것처럼 변명해야합니다 . 선택할 수있는 것은위원회가 당신에게 특정한 것을 강제로 먹이는 것을 귀찮게하지 않았기 때문에 부끄러운 일입니다 ...
DevSolar

19
@DevSolar는 거의 2 번째 계정을 만들어 그 의견에 대한 또 다른 찬사를 보냅니다
사용자

15
@DevSolar System.Net는 강요되지 않으며 언어에 포함 된 모든 .NET 권장 사항을 따르는 고품질 라이브러리입니다. 대체 구현이 있지만 표준 라이브러리에서 HTTP를 지원한다는 것은 간단한 앱 작성이 간단하고 타사 라이브러리 간의 상호 운용성이 향상되고 종속성이 적고 정면을 쉽게 구현할 수 있음을 의미 std::string합니다. 그들 자신의 도서관은 그것과 함께 오는 모든 어려움을 상상하십시오.
Athari

17
@DevSolar : urllib2는 타사 가 아닙니다 . <iostream>C ++에서 와 같이 stdlib에 있습니다. urllib2Python 에서는 C ++ 과 달리 항상 사용할 수 있습니다 <boost/asio.hpp>. 타사 모듈을 사용할 수있는 경우 나는 파이썬에서 lxml또는 BeautifulSoup파이썬을 사용할 것이다 .
jfs

22
또한 여기서 가장 중요한 의견은 C ++이 표준 라이브러리에서 다른 언어만큼 많은 것을 표준화하지는 않지만 언어로 표준적인 많은 동일한 작업을 위해 널리 사용되는 강력한 휴대용 라이브러리가 여전히 있다고 생각합니다. 파이썬처럼,이 라이브러리 중 일부는 사실상의 표준입니다. 그리고이 중 일부는 C ++이 작은 바이너리와 작은 라이브러리가있는 임베디드 시스템을 대상으로 할 수있는 결과입니다.
Peter Cordes

85

Linux / OS X의 순수 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
파이프에 유닉스 파일 핸들을 사용하는 것과 같습니다.
javadba

2
와우, 외부 유틸리티 없이는 이것을 할 수 있다고 생각하지 않았습니다. 비록 그것이 LFS에 내 배쉬 3.2.17이 조금 쓸모없는 것 같아서 지원하지 않습니다 mapfile:)
Ruslan

@Ruslan Yep mapfile은 bash 4.x와 함께 제공됩니다. while read루프에서도 완전히 같은 일을 할 수 있습니다.
Digital Trauma

3
@Ruslan while read대신로 변경했습니다 mapfile. 더 휴대하기 쉽고 읽기 쉽다고 생각합니다.
Digital Trauma

1
OS X에서도 작동합니다!
Alex Cohn

65

파이썬 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 %가 내가 작업하는 모든 프로젝트에서 이미 수행됩니다.
Dunk

20
@Dunk : 예에서 일부 예외가 발생했다고 가정합니다 (예 : from urlopen()). 충돌 및 사망 이외의 예외로 무엇을해야합니까? 어쨌든 충돌하고 죽을 경우, 파이썬이 충돌과 죽기를 처리하게하고 예외 처리를 완전히 없애지 않는 이유는 무엇입니까?
Kevin

8
@ 덩크 : 다른 사람의 파이썬 코드를 사용하고 있다면 오류를 잡는 것보다 오류를 잡지 않는 것이 좋습니다. 그들이 후자를한다면, 나는 잡을 필요가있다 . 그것은 결코 재미 없다. urlopensys.exit("something's borked!")SystemExit
Kevin

55

씨#

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몇 글자를 깎을 수 있습니다 .
Superbest

15
@Superbest 나는 이름을 하나의 문자로 만들 수 있고 html변수를 완전히 제거 할 수는 있지만 내가 추구 하는 것은 아닙니다.
Athari

6
@Superbest 코드 골프가 아닙니다 . : D
Kroltan

5
글쎄, 그것은 또한 가독성을 향상시킵니다. var코드 의미에 영향을 미치지 않을 때 사용하지 않는 이유 가 있습니까?
Superbest

6
@Superbest : "가독성을 향상시킵니다"는 주관적입니다. 개인적으로 변수 유형을 명시 적으로 명시하면 가독성이 향상됩니다 (일반적으로 여기 코드와 같이). 그러나 나는 이것을 토론하고 싶지 않다. 대안 적 관점이 존재한다는 것을 지적하고 싶습니다.
Cornstalks

54

"타사 없음"은 오류입니다

"타사 없음"가정이 오류라고 생각합니다. 그리고 C ++에서 재사용 가능한 코드를 만들기가 너무 어렵 기 때문에 C ++ 개발자에게 고통을주는 특정 오류입니다. 작은 스크립트라도 아무 것도 개발할 때는 항상 재사용 가능한 코드를 사용할 수 있습니다.

문제는 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
써드 파티 라이브러리의 요점을 해결하기 위해 찬성하지만 C ++에서 재사용 가능한 코드만드는 것은 다른 언어와 마찬가지로 쉽게 할 수 있습니다. 재사용 가능한 코드를 사용 하고 특히 찾는 것은 어려울 수 있지만, 심각하게 문제가되는 유일한 것은 컴파일 된 아티팩트를 재사용하는 것이지만 종종 Perl과 같은 해석 된 언어에서는 문제가되지 않습니다.
Martin Ba

4
비유를 늘리기 위해 Boost는 CPAN과 비슷합니다. 당신이 사용하지 않는 많은 것들이 있기 때문에 CPAN을 "몬스터의 코드 저장소"라고 부르지 않습니까?
Martin Ba

22
CPAN은 입니다 그 4 개 단어의 합리적인 정의에 의한 '코드 괴물 저장소'.
jwg

3
@MartinBa C ++은 컴파일 언어이므로 동의하지 않습니다. ABI 호환성을 유지하기가 어렵 기 때문에 모든 실행 파일이 종속성의 전체 스택을 다시 작성해야하므로 코드 재사용 성이 심각하게 저해됩니다. C ++에서 재사용 가능한 라이브러리를 생성하려면 항상 ABI와 호환되지 않는 변경 사항을 강요하지 않도록 긴 시간을 거쳐야합니다.
Daniel Ruoso

6
@MartinBa 간단한 작업을 구현할 때마다 전체 유니버스를 다시 작성해야하기 때문에 참을 수 없습니다.
Daniel Ruoso

47

유닉스 쉘

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을 수행 할 수 없는지, 또는 문제를 해결하기위한 프로그램을 작성하고 방금 수행 할 프로그램을 호출했기 때문에 -1을 해결할 수 없습니다. 블라 잉.
David Richerby

2
Lynx를 curl 또는 wget으로 바꾸는 것이 좋습니다. 웹 페이지를 다운로드하는 데 더 일반적으로 사용됩니다.
Pavel Strakhov

4
@PavelStrakhov 나는 특별한 작업을 수행하지 않고 링크를 덤프 할 수 있기 때문에 lynx를 선택했습니다 :)
Ruslan

2
@SteveJessop "특별한"은 실제로 구문 분석 또는 정규식 또는 무엇이든 의미합니다. lynx를 사용하면 링크 목록 (컬 및 wget이 나열되지 않음)을 제거하고 번호 매기기를 제거하십시오. 당신은 그것이 부정 행위 나 다른 것을 고려할 수도 있지만 , 출력을 미세 조정하는 것만 으로도 { 필요한 것을 거의 완벽하게 수행 하는 도구를 사용 }하는 것이 재미 있다고 생각했습니다 .
Ruslan

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(주 !importantbackground). 더 많은 스타일을 가진 다른 페이지에서 작업하려면 확장해야합니다 (더 많은 속성을 재설정하고 속성을 중요한 것으로 표시 등).

해시로 시작하는 인트라 페이지 링크를 제외하고 상대 링크를 포함하는 대체 버전 (안타깝게도 하드 코딩 된 절대 링크에 의존 함) :

* {
  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 2016 년

36

클로저

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

27
아저씨? Clojure를 배워야합니다.
11684

10
@ 11684 - Clojure의도라는 이름의 표준 기능을 가지고 spit, zipper그리고 lazy-cat... :-)
밥 자비스

2
와우, 나는 그것이 늦게 새해 결심이 될 것이라고 생각합니다. @BobJarvis
11684

30

이맥스 리스프

(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
모든 줄을 한 줄로
묶으

무엇에 대해 ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl-이것은 단지 한 줄이 아니라 하나의 표현 입니다. C ++ 코드에서 줄 바꿈을 모두 삭제할 수는 있지만 전체 작업을 단일 식으로 수행하는 것과 동일하지 않습니다.
DaoWen

4
@DaoWen : 죄송하지만 표현식 대 라인을 시작하는 것은 어리석은 일입니다. 펑터와 C ++를 추가하면됩니다. 그러나 이것은 libs가 "granted"로 간주되고 "zero code inside"로 간주되는 문제입니다. 그것은 줄 서두를 가독성으로 포장한다는 사실을 바꾸지 않습니다. 여전히 하나의 표현식으로 유지하고 몇 줄로 다시 포맷하면 .. 줄 수 이외의 많은 것을 얻을 수 있습니다. 그게 내 요점이야 바보 같은 포장-C ++도 가능합니다. 누군가가 "실리 포장"상자에서 벗어나려면 행 수가 아닌 가독성을 위해 코드 형식을 지정해야합니다.
quetzalcoatl

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 만 출력)
primo

귀하의 의견에 감사드립니다
David Xu

@DavidXu 고치지 않았다면 ...?
Shahar

이제는 고정되었습니다.!
David Xu

25

PowerShell

정규화 된 모든 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

8
당신은 컬렉션을 평평 할 PowerShell을의 열망을 남용 수 : (iwr "http://www.stroustrup.com/C++.html").Links.href(또는 (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"유일한 절대 URI의 경우)
마티아스 R. Jessen

1
꽤 편리합니다!
Justin Dunlap

22

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 문을 버리고 다른 줄을 줄일 수 있습니다.
Unihedron

@Unihedro 않습니다.
TimWolla

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')요청을 단축하고 읽을 수 있도록 유지하는 데 사용할 수 있습니다. 따라서 전체 코드는 한 줄에있을 수 있습니다 (읽기 가능하게 유지) puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). 함께 실행하면 라인이 ruby -rnet/http필요하지 않습니다 require 'net/http'.
Hauleth

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

1
이것은 약간의 규칙을 스트레칭으로보고도 않습니다 Network.HTTPTextRegex.Posixbase패키지로 제공된다. (그들은 Haskell 플랫폼에 있고 물론 Hackage에도 있습니다.)
반 시계 회전을 중단

1
@ JanDvorak, 나는 ghci로 작성하기 시작합니다 (아마도 변경하지 말고 게시해야합니다). 그러나 귀하의 메모는 관련이 있습니다. 감사합니다.
vlastachu

@leftaroundabout은 몰랐다. 기본 패키지를 사용한 경우 수행 할 수없는 것 같습니다.
vlastachu

networkbase둘 중 하나도 아니므로 자신의 소켓 바인딩을 롤링하기 위해 저장하십시오. 실제로 할 수있는 방법은 없습니다 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대신에 절름발이 를 사용할 수 있습니다 . 대괄호를 생략 할 수도 있습니다. 나는 확실하지 않지만, iirc 당신은 잘 떨어 뜨릴 수 있고 (체계없이) 떠날 수 있습니다. . truein_arrayhttp://
카이저

그리고 : 또 다른 가능성은의 if ( ) {}찬성 을 떨어 뜨리는 것 입니다 in_array() and print $url.PHP_EOL. 하지만 그래, 당신을 위해 (내가 할 수있는 경우) 다른 하나를 얻을 것입니다 최고의 가독성 :
카이저

예제를 시도하고 엄격한 표준 (PHP 5.4)에 대한 오류가 발생했습니다. 소스와 같이, 세미콜론이 누락되었거나 손상되었거나 형식이 잘못된 링크가있을 수 있습니다. 을 사용하여 오류보고를 끌 수 있습니다 @\DOMDocument. 그냥 시도하고 작동하는지 확인할 수 있습니다.
카이저

아냐, 그건 잘못된 문서 야. 기술적으로 당신은 ::loadHTMLFile()정적으로 호출해서는 안되며 , 추가 @하는 것은 그 인공물을 숨 깁니다.
Jack

2
이것은 확실히 가장 "올바른"솔루션 중 하나이며, 프로덕션 환경에서 사용할 수있는 유일한 솔루션 중 하나입니다. 좋은 직업
Jordon Biondo

14

유닉스 쉘

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

7
"타사 라이브러리는 허용되지 않습니다" . 나는 wgetbash와 마찬가지로 GNU 이기 때문에 타사가 아니라고 주장 할 수 있습니다. 그러나 curl분명히 타사입니다.
디지털 외상

무엇에 대한 ftp://ftp.research.att.com/pub/c++std/WP/CD2그리고 https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

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

를 사용하면 Scanner링크의 정규식 패턴을 직접 처리하고 Scanner의 결과를 반복 할 수 있습니다.
Holger

5
그래 .. 그것은 당신을 위해 자바입니다. 코드 골프에 사용하는 것은 용감한 일입니다.
javadba

4
실제로 C ++보다 짧은 Java 솔루션을 볼 줄은 몰랐습니다!
slebetman

2
마지막 의견 수정 :이 코드는 Java로 작성할 수있는 가장 짧고 가장 깨끗한 코드임을 인정해야합니다. 람다로 더 짧아 질 수있는 SAX 파서 접근법을 시도했지만 웹 페이지가 XHTML이 아니며 파서에서 예외가 발생합니다. 정규식이 유일한 방법입니다.
Mister Smith

11

멋진, 근사한

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

?를 사용하여 향상시킬 수 있습니다. 운영자는 NPE를 피하기 위해?
Chris K

2
@ChrisKaminski이고 오류를 확인하기 위해 여기에서 가장 먼저 (Bjarne 옆에) 있습니까? 못! 그 외에도 : IO 관련 예외 만 여기에 표시됩니다. NPE는 어디에 있습니까?
cfrick

findAll ()은 null을 반환 할 수 있습니다. 아니면 빈 목록을 반환합니까? 여전히 Groovy에 약간 익숙합니다. 편집 : nm, findAll ()이 빈 목록을 반환하는 것처럼 보입니다. 그루비 사람들은 정말 똑똑 했어요 :-)
Chris 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

나는 그것을 얻는다. "링크". :-)
Jack at SAP Canada

10

CoffeeScript / NodeJS

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

1
이것이 CoffeeScript / Node 인 것 같아요? 당신이 그것을 지정해야 할 것 같아요 ...
John Dvorak

와. 매우 읽기 쉽습니다.
slebetman

@slebetman 그것은 확실히 작지만
John Dvorak

@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

@DanielRuoso는 동의했다.
primo

심지어 use v5.10;say for $response->content...
마크 리드

나는 각자 자신에게 생각합니다. 백 포트 된 perl6 기능 중 일부는 문제가 있었지만 (스마트 매칭, 당신을보고 있습니다) say매우 유용합니다. (또한 지난 13 년 동안 perl5에 대해 완전히 관련이없는 perl6ism 개선이 많이있었습니다. 체크 아웃 할 가치가 있습니다.)
Mark Reed

@MarkReed 나는 say이 경우 특히 펄에 익숙하지 않은 사람들에게 더 읽기 쉽다는 것에 동의한다 .
primo

9

아르 자형

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

목표 -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
뭐? 스위프트 버전을 작성하십시오. 그 대괄호 넌센스는 내 눈을 아프게합니다 :)
Mister Smith

2
[]에 대한 만세! 또한 스몰 토크 버전을 완전히 추가해야합니다.)
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]

puts 내에서 http :: data를 수행하여 도망 갈 수 있습니다. 임시 변수를 만들 필요가 없습니다. 또한 줄 바꿈과 들여 쓰기를하여 형식을 지정합니다 [. 그러나 그것은 스타일 선택입니다.
slebetman

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

추신 : 이 코드는 전체 소스를 메모리로 읽으므로 regexp.FindReaderIndex스트림 검색을 사용하여 앱을 방탄으로 만듭니다.


6

CJam

CJam에는 정규 표현식이 없으므로이 접근법에서 다른 접근법을 사용해야했습니다.

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

먼저 모두 '를 로 변환 "한 다음 모두 를 분할하고 모든 "대체 문자열을 취한 다음 마지막으로 http://또는로 시작하는 문자열에 대해 해당 목록을 필터링합니다 https://. 그런 다음 필터링 된 각 문자열을 새 줄에 인쇄하십시오.

사용하여 시도 자바 인터프리터 등을

java -jar cjam-0.6.2.jar file.cjam

여기서 file.cjam에는 위 코드의 내용이 있습니다.


9
읽을 수있는 부분에 대해 모른다 ... Cjam에 웹 기능이 있다는 것을 몰랐다
Def

당신은 골프가 ... 원하는 경우 ''/'"f/:+''/'"*'"/'"f/0f=.
jimmy23013

... 왜 기다려 '"f/0f=? 그게 뭔가를해야합니까 ( 2%예 :)?
jimmy23013

6

에프#

이 코드는 훨씬 짧을 수 있지만이 코드를 다시 읽거나 사용해야하므로 불필요한 유형 주석이 많을 경우 이와 같이 작성합니다. 표준 CLR 유형 Match 에 대해 패턴 일치를 활성화하기 위해 활성 패턴 MatchValue 를 사용 하는 방법을 보여줍니다.

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

@MichalMa 나는 함수의 이름 자체가 충분히 표현 적이라는 것에 동의한다. html 및 링크 변수는 실용적인 이유로 거기에있다. repl에서는 아마도 List.iter를 사용했을 것 같지만 더 많이 읽는 방식을 좋아하기 때문에 List.iter 대신 for 루프를 사용했습니다.
SourceSimian
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.