Gỡ lỗi Stroustrup Việc gỡ lỗi huyền thoại C ++ chỉ dành cho các chương trình lớn, phức tạp, chỉ


161

Stroustrup gần đây đã đăng một loạt các bài đăng vạch trần những huyền thoại phổ biến về C ++ . Huyền thoại thứ năm là: Chỉ C ++ dành cho các chương trình lớn, phức tạp, chỉ có. Để gỡ lỗi, anh ta đã viết một chương trình C ++ đơn giản tải xuống một trang web và trích xuất các liên kết từ nó . Đây là:

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

Hãy cho Stroustrup biết chương trình nhỏ và dễ đọc thực sự là gì.

  1. Tải xuống http://www.stroustrup.com/C++.html
  2. Liệt kê tất cả các liên kết:

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

Bạn có thể sử dụng bất kỳ ngôn ngữ nào, nhưng không cho phép thư viện của bên thứ ba.

Người chiến thắng

Câu trả lời của C ++ đã giành được bằng phiếu bầu, nhưng nó dựa vào thư viện của bên thứ ba (không được phép theo quy tắc) và cùng với một đối thủ cạnh tranh thân thiết khác là Bash , dựa vào ứng dụng khách HTTP bị hack (nó sẽ không hoạt động với HTTPS, gzip, chuyển hướng, v.v.). Vì vậy, Wolfram là một người chiến thắng rõ ràng. Một giải pháp khác gần gũi về kích thước và khả năng đọc là PowerShell (với sự cải thiện từ các bình luận), nhưng nó đã không nhận được nhiều sự chú ý. Các ngôn ngữ chính ( Python , C # ) cũng đến khá gần.


43
Đối với mỗi anh ấy, tôi đã được gọi là tồi tệ hơn. Nếu mục tiêu của OP không cố gắng và bằng cách nào đó chứng minh rằng Stroustrup là sai, thì tôi đồng ý với đánh giá của bạn. Nhưng toàn bộ tiền đề của câu hỏi là chỉ ra làm thế nào "ngôn ngữ yêu thích của bạn" có thể làm điều tương tự như 50 dòng C ++ này trong ít dòng mã hơn. Vấn đề là không có ví dụ nào làm điều tương tự. Cụ thể, không có câu trả lời nào thực hiện bất kỳ kiểm tra lỗi nào, không có câu trả lời nào cung cấp các chức năng có thể sử dụng lại, hầu hết các câu trả lời không cung cấp một chương trình hoàn chỉnh. Ví dụ Stroustrup cung cấp tất cả điều đó.
Dunk

19
Điều đáng buồn là trang web của anh ta thậm chí không hợp lệ UTF-8 . Bây giờ tôi phải giải quyết vấn đề đó, mặc dù quảng cáo máy chủ của anh ấy Content-Type: text/html; charset=UTF-8... Tôi sẽ gửi email cho anh ấy.
Bắp ngô

27
@Dunk Các ví dụ khác không cung cấp các chức năng có thể sử dụng lại vì chúng hoàn thành toàn bộ chức năng của các chức năng đó trong một dòng và không có ý nghĩa gì khi tự mình thực hiện toàn bộ chức năng đó và ví dụ C ++ không thực hiện bất kỳ kiểm tra lỗi nào điều đó không được xử lý nguyên bản theo cách gần như giống hệt nhau và cụm từ "chương trình hoàn chỉnh" gần như vô nghĩa.
Jason

16
"Bạn có thể sử dụng bất kỳ ngôn ngữ nào, nhưng không cho phép thư viện của bên thứ ba." Tôi không nghĩ rằng đó là một yêu cầu công bằng khi xem xét boost/asiođược sử dụng ở đó thư viện của bên thứ ba. Ý tôi là làm thế nào các ngôn ngữ không bao gồm tìm nạp url / tcp như một phần của thư viện chuẩn của nó sẽ cạnh tranh?
Greatwolf

Câu trả lời:


116

Sói

Cảm giác như gian lận hoàn toàn

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

Vì vậy, chỉ cần thêm một số phân tích trung thực trên đầu trang

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

49
Không, tôi không thấy bất kỳ gian lận nào ở đây. Thách thức này là về việc đưa ra ngôn ngữ tốt nhất của bạn. Và dòng đầu tiên đó là mẫu mực của "nhỏ và có thể đọc được".
Martin Ender

Một câu trả lời có thể bỏ qua các lập luận ngớ ngẩn về việc bắt các liên kết ftp. Xuất sắc.
Seth Battin

Đến đây để cung cấp giải pháp chính xác này, vui mừng khi thấy những người khác cũng đánh giá cao nó.
Michael Stern

@ MartinBüttner Trong trường hợp đó, bạn có thể muốn xem xét hạ cấp meta.codegolf.stackexchange.com/a/1078/12130
David Mulder

6
@DavidMulder Về mặt kỹ thuật, kẽ hở hiện không hợp lệ, vì tỷ lệ bỏ phiếu là + 41 / -21 (và câu hỏi kẽ hở nói rằng kẽ hở được chấp nhận nếu có ít nhất gấp đôi số lần upvote so với downvote). Một cuộc gọi gần gũi, thừa nhận, nhưng vẫn còn. ;) Hơn nữa, đây là một cuộc thi phổ biến, không phải là môn đánh gôn, và đặc biệt, đó là một cuộc thi về việc cho thấy việc này có thể được thực hiện dễ dàng như thế nào trong một ngôn ngữ nhất định, đó là lý do tại sao tôi nghĩ rằng lỗ hổng không thực sự áp dụng cho thử thách này dù sao đi nữa (vì thách thức về cơ bản là yêu cầu nó).
Martin Ender

115

C ++

#include <boost/asio.hpp>
#include <regex>
#include <iostream>
int main() {
    std::string server = "www.stroustrup.com";
    std::string request = "GET http://" + server + "/C++.html HTTP/1.0\r\nHost: " + server + "\r\n\r\n";
    boost::asio::ip::tcp::iostream s{server, "http"};
    s << request;
    std::regex pat{R"((http://)?www([./#\+-]\w*)+)"};
    std::smatch m;
    for (std::string l; getline(s, l);)
        if (std::regex_search(l, m, pat))
            std::cout << m[0] << "\n";
}

Thiếu sót chính là bản chất khó xử của boost :: asio, tôi chắc chắn rằng nó có thể còn ngắn hơn với một thư viện tốt hơn.


166
Thật buồn cười là "không có thư viện của bên thứ ba" có nghĩa là Python vẫn có thể import urllib2, C3 vẫn có thể using System.Net, Haskel vẫn có thể import Network.HTTP, nhưng một lập trình viên C ++ phải kiếm cớ #include <boost/asio.hpp>như thể có một số liệu crapton của các thư viện C ++ (và C!) Được xây dựng có mục đích sẵn sàng để lựa chọn là điều đáng xấu hổ chỉ vì ủy ban không bận tâm đến việc cho bạn ăn một thứ cụ thể ...
DevSolar

19
@DevSolar gần như đã tạo một tài khoản thứ 2 để cung cấp cho bạn một upvote khác cho nhận xét đó
người dùng

15
@DevSolar System.Netkhông bị ép buộc, đây chỉ là một thư viện chất lượng cao theo tất cả các đề xuất .NET có trong ngôn ngữ. Có các triển khai thay thế, nhưng có hỗ trợ HTTP trong thư viện tiêu chuẩn có nghĩa là viết các ứng dụng đơn giản là đơn giản, có nghĩa là khả năng tương tác tốt hơn giữa các thư viện bên thứ ba, có nghĩa là ít phụ thuộc hơn, có nghĩa là triển khai dễ dàng cho mặt tiền, v.v. Hãy tưởng tượng một thế giới không có std::string, hãy tưởng tượng cách mọi người sử dụng thư viện riêng của họ, hãy tưởng tượng tất cả những khó khăn đi kèm với nó.
Athari

17
@DevSolar: không phảiurllib2 là bên thứ 3. Đó là trong stdlib như trong C ++. trong Python luôn có sẵn không giống như trong C ++. Nếu chúng tôi được phép sử dụng các mô-đun của bên thứ 3; Tôi sẽ sử dụng hoặc trong Python. <iostream>urllib2<boost/asio.hpp>lxmlBeautifulSoup
JFS

22
Ngoài ra, tôi nghĩ rằng nhận xét quan trọng nhất ở đây là C ++ không tiêu chuẩn hóa nhiều thứ trong các thư viện tiêu chuẩn của nó như các ngôn ngữ khác, nhưng vẫn có các thư viện di động mạnh mẽ được sử dụng rộng rãi cho nhiều tác vụ giống nhau theo tiêu chuẩn trong các ngôn ngữ như python, và một số lib này gần như là một tiêu chuẩn thực tế. Và một số điều này là kết quả của việc C ++ có thể nhắm mục tiêu các hệ thống nhúng với các tệp nhị phân nhỏ và thư viện nhỏ.
Peter Cordes

85

Pure Bash trên Linux / OS X (không có tiện ích bên ngoài)

Phần mềm máy khách HTTP nổi tiếng là cồng kềnh. Chúng tôi không muốn những loại phụ thuộc. Thay vào đó, chúng ta có thể đẩy các tiêu đề thích hợp xuống luồng TCP và đọc kết quả. Không cần phải gọi các tiện ích cổ xưa như grep hoặc sed để phân tích kết quả.

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 - Tôi cho rằng nó có thể dễ đọc hơn ...


1
Giống như cái này sử dụng tay cầm tập tin unix cho các đường ống.
javadba

2
Wow, không bao giờ nghĩ rằng một người có thể làm điều này mà không cần dụng cụ bên ngoài. Mặc dù có vẻ như bash 3.2.17 của tôi trên LFS là một chút lỗi thời vì vậy nó không hỗ trợ mapfile:)
Ruslan

@Ruslan Yep, mapfileđi kèm với bash 4.x. Điều tương tự là hoàn toàn có thể làm được với một while readvòng lặp là tốt.
Chấn thương kỹ thuật số

3
@Ruslan Tôi đổi nó thành while readthay vì mapfile. Di động hơn và dễ đọc hơn, tôi nghĩ.
Chấn thương kỹ thuật số

1
Hoạt động trên OS X cũng vậy!
Alex Cohn

65

Con trăn 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, nhưng làm việc


9
Tại sao không xâu chuỗi nhiều cuộc gọi đó? l = re.findall('"((http)s?://.*?)"', u.urlopen(s).read())
Tên giả

13
Nó ngắn nhưng không phải là thành ngữ (tính dễ đọc trong Python)
jfs

24
Hmmm ... nếu tất cả các mã của tôi bỏ qua các lỗi như ví dụ này thì 75% đến 90% công việc của tôi sẽ được thực hiện trên mọi dự án tôi làm.
Dunk

20
@Dunk: Giả sử ví dụ đã bắt được một số ngoại lệ (ví dụ: từ urlopen()). Nó nên làm gì với một ngoại lệ như vậy, ngoài sự cố và chết? Nếu nó sẽ sụp đổ và chết đi, tại sao không để Python xử lý sự cố và chết, và loại bỏ hoàn toàn việc xử lý ngoại lệ?
Kevin

8
@Dunk: Nếu tôi đang sử dụng mã Python của người khác, tôi muốn họ không bắt urlopenlỗi hơn (nói) bắt họ và gọi sys.exit("something's borked!"). Nếu họ làm sau, tôi phải bắt SystemExit, điều đó không bao giờ vui.
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
Bạn có thể sử dụng var html, và có lẽ var matchđể cạo một vài ký tự.
Tuyệt vời nhất vào

15
@Superbest Tôi cũng có thể đặt tên một ký tự và loại bỏ htmlbiến hoàn toàn, nhưng đó không phải là những gì tôi theo sau.
Athari

6
@Superbest không mã golf . : D
Kroltan 7/1/2015

5
Vâng, nó cũng cải thiện khả năng đọc. Có bao giờ một lý do để không sử dụng varkhi nó sẽ không ảnh hưởng đến ngữ nghĩa mã?
Tuyệt vời nhất vào

6
@Superbest: "nó cải thiện khả năng đọc" là chủ quan. Cá nhân, tôi nghĩ rằng việc nêu rõ loại biến giúp cải thiện khả năng đọc (thông thường, như trong mã này ở đây). Tôi không muốn tranh luận về điều này, mặc dù; Tôi chỉ muốn chỉ ra rằng các quan điểm thay thế tồn tại.
Bắp ngô

54

"Không có bên thứ ba" là một ngụy biện

Tôi nghĩ rằng giả định "không có bên thứ ba" là sai lầm. Và là một sai lầm cụ thể ảnh hưởng đến các nhà phát triển C ++, vì rất khó để tạo mã có thể sử dụng lại trong C ++. Khi bạn đang phát triển bất cứ điều gì, ngay cả khi đó là một tập lệnh nhỏ, bạn sẽ luôn sử dụng bất kỳ đoạn mã có thể tái sử dụng nào có sẵn cho bạn.

Vấn đề là, trong các ngôn ngữ như Perl, Python, Ruby (để đặt tên cho một số ít), việc sử dụng lại mã của người khác không chỉ dễ dàng, mà đó là cách mà hầu hết mọi người thực sự viết mã hầu hết thời gian.

C ++, với các yêu cầu ABI gần như không thể duy trì tương thích của nó làm cho công việc khó khăn hơn nhiều, bạn kết thúc với một dự án như Boost, một kho lưu trữ mã khổng lồ và rất ít khả năng kết hợp bên ngoài nó.

Một ví dụ CPAN

Để giải trí, đây là một ví dụ dựa trên CPAN, với phân tích cú pháp html đúng, thay vì cố gắng sử dụng regex để phân tích cú pháp 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
Upvote để giải quyết vấn đề của libs bên thứ 3, nhưng: tào lao, làm cho có thể tái sử dụng trong C ++ cũng dễ dàng như trong ngôn ngữ khác. Việc sử dụng và đặc biệt là tìm có thể tái sử dụng có thể khó hơn một chút, nhưng điều duy nhất có vấn đề nghiêm trọng là sử dụng lại các tạo phẩm được biên dịch , nhưng đó thường không phải là vấn đề trong các ngôn ngữ được giải thích như Perl, v.v.
Martin Ba

4
Để kéo dài sự tương tự, Boost giống như CPAN - chọn và chọn. Bạn không gọi CPAN là "kho mã khổng lồ" chỉ vì có quá nhiều thứ trong đó bạn không sử dụng?
Martin Ba

22
CPAN một "kho lưu trữ mã khổng lồ", theo bất kỳ định nghĩa hợp lý nào về bốn từ đó.
JWG

3
@MartinBa Tôi không đồng ý, C ++ là ngôn ngữ được biên dịch, yêu cầu mọi thực thi phải xây dựng lại toàn bộ phụ thuộc của nó vì khó duy trì khả năng tương thích ABI cản trở nghiêm trọng khả năng sử dụng lại mã. Để tạo thư viện có thể sử dụng lại trong C ++, bạn phải trải qua thời gian rất dài để đảm bảo rằng bạn không ép buộc bản thân vào các thay đổi không tương thích ABI mọi lúc.
Daniel Ruoso

6
@MartinBa vì phải xây dựng lại toàn bộ vũ trụ mỗi khi bạn muốn thực hiện một nhiệm vụ đơn giản là không thể chịu nổi.
Daniel Ruoso

47

Vỏ UNIX

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

Cũng tìm thấy một ftp://liên kết :)

Một cách khác, không dựa vào ://cú pháp:

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

38
Tôi không thể biết nên +1 vì sử dụng trình duyệt web để tải xuống trang web là công cụ phù hợp cho công việc hoặc -1 vì thử thách là viết chương trình để làm blahblahblah và bạn chỉ cần gọi một chương trình để làm sự bỉ ổi
David Richerby 7/1/2015

2
Tôi nghĩ tốt hơn là thay thế lynx bằng curl hoặc wget. Chúng thường được sử dụng để tải xuống một trang web.
Pavel Strakhov

4
@PavelStrakhov Tôi đã chọn lynx chính xác bởi vì nó có thể kết xuất các liên kết mà không cần tôi làm gì đặc biệt :)
Ruslan

2
@SteveJessop bởi "đặc biệt" Tôi có nghĩa là thực sự phân tích cú pháp hoặc regexing hoặc bất cứ điều gì. Với lynx tôi chỉ cần grep ra danh sách các liên kết (mà curl và wget không liệt kê) và xóa đánh số. Bạn có thể coi đó là gian lận hoặc bất cứ điều gì, nhưng tôi nghĩ thật thú vị khi {sử dụng công cụ gần như hoàn hảo những gì được yêu cầu}, chỉ cần tinh chỉnh đầu ra.
Ruslan

7
"nhưng không cho phép thư viện của bên thứ ba" . Tôi cho rằng đó lynxlà chức năng tương đương với thư viện của bên thứ ba trong kịch bản này.
Chấn thương kỹ thuật số

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

Mã này có thể được sử dụng làm kiểu người dùng để chỉ hiển thị các liên kết tuyệt đối trên một trang trong danh sách không được định dạng. Nó có thể không hoạt động chính xác nếu trình duyệt của bạn thực thi kích thước phông chữ tối thiểu.

Nó hoạt động chính xác với http://www.stroustrup.com/C++.html(lưu ý !importanttrên background). Để làm việc trên các trang khác có nhiều kiểu hơn, nó phải được mở rộng (đặt lại nhiều thuộc tính, đánh dấu các thuộc tính là quan trọng, v.v.).

Phiên bản thay thế bao gồm các liên kết tương đối ngoại trừ các liên kết intrapage bắt đầu bằng băm (không may, nó phụ thuộc vào một liên kết tuyệt đối được mã hóa cứng, không may):

* {
  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
Đây là điều tồi tệ nhất tôi từng thấy. +1
Emmett R.

1
Điều này thật đẹp và hoàn toàn kinh hoàng. +1
ricdesi

36

Clojure

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

28
Nhếch nhác?! Tôi cần học Clojure.
11684

10
@ 11.684 - Clojure cũng có chức năng tiêu chuẩn đặt tên spit, zipperlazy-cat... :-)
Bob Jarvis

2
Ồ, tôi nghĩ đó sẽ là một Nghị quyết cuối năm mới. @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
Tôi hơi thất vọng, vì mã này nhỏ gọn và dễ đọc đến mức nào, rằng nó không có nhiều phiếu bầu hơn. Làm tốt.
Spacemoose

28

Scala

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

8
đóng gói mọi thứ trong một dòng - C ++ cũng có thể làm điều đó
quetzalcoatl

Thế còn ftp://ftp.research.att.com/pub/c++std/WP/CD2?
Tobias Kienzler

22
@quetzalcoatl - Đây là một biểu thức , không chỉ một dòng. Bạn chỉ có thể xóa tất cả các ngắt dòng khỏi mã C ++, nhưng đó không giống như thực hiện toàn bộ tác vụ trong một biểu thức.
DaoWen

4
@DaoWen: Xin lỗi, nhưng bắt đầu biểu thức-vs-line chỉ là ngớ ngẩn. Thêm một số functor và C ++ bạn cũng có thể làm điều đó. Nhưng đó chỉ là câu hỏi về những gì libs được coi là "được cấp" và có "không có mã bên trong". Nó không thay đổi thực tế là đóng gói nó thành một dòng dễ đọc. Người ta có thể giữ nó như một biểu thức duy nhất và chỉ định dạng lại nó thành một vài dòng để thu được nhiều và không mất gì ngoài .. đếm dòng. Đó là quan điểm của tôi. Đóng gói ngớ ngẩn - C ++ cũng có thể làm điều đó. Nếu ai đó muốn thoát ra khỏi hộp "đóng gói ngớ ngẩn", thì nên định dạng mã cho dễ đọc, không phải linecount.
quetzalcoatl

3
@quetzalcoatl Tobias đã không đặt liên kết ở đó để chúng tôi theo dõi nó. Anh ấy đã hỏi người viết câu trả lời này tại sao nó không có trong kết quả của anh ấy.
JLRishe

25

PHP 5

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

5
Các chỉnh sửa được đề xuất: '/"((http)s?://.*?)"/''|"((http)s?://.*?)"|'(hiện đang xảy ra lỗi); loại bỏ array_unshift($m);(hiện tại là một lỗi, bạn có thể có nghĩa là array_shiftthay thế); print_r($m);print_r($m[1]);(chỉ ra các url).
Primo

đã sửa, cảm ơn về đầu vào của bạn
David Xu

@DavidXu Ngoại trừ bạn không sửa nó ...?
Shahar

bây giờ đã được sửa.!
David Xu

25

PowerShell

Tìm kiếm văn bản cho tất cả các URL đủ điều kiện (bao gồm JavaScript, CSS, v.v.):

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

Hoặc để nhận liên kết chỉ trong các thẻ neo (bao gồm các URL tương đối):

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

Các phiên bản ngắn hơn từ ý kiến:

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

6
Nếu bất cứ ai tự hỏi, iwrlà một bí danh cho Invoke-WebRequest(PS3 +).
Athari

8
Bạn có thể lạm dụng sự háo hức của PowerShell để làm phẳng các bộ sưu tập và thực hiện: (iwr "http://www.stroustrup.com/C++.html").Links.href(hoặc (iwr "http://www.stroustrup.com/C++.html").Links.href-match":"chỉ dành cho URI tuyệt đối)
Mathias R. Jessen

1
Điều đó khá tiện dụng!
Justin Dunlap

22

CƯỜI MỞ MIỆNG

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

Để làm cho danh sách tương tự như ví dụ ban đầu, bạn có thể dẫn đầu ra của chương trình thông qua | sort | uniqhoặc thay vào đó thêm import std.arrayvà thay đổi dòng .filter!("a")){ writeln(_.front[1]); }vào đây : .filter!("a").map!(a => a.front[1]).array.sort.uniq){ writeln(_); }. Lưu ý, tuy nhiên, tôi chỉ thử mã này và không chứng minh nó là chính xác hoặc "thành ngữ". :)
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
Tôi tự hỏi nếu require('http').getlàm việc. Nếu có thì chúng ta có thể bỏ câu lệnh var và rút ngắn dòng khác.
Unihedron

@Unihedro Nó làm.
TimWolla

9
@Unihedro Nó có, nhưng đây không phải là một cuộc thi golf.
cPu1

Bạn không cần phải sử dụng bất kỳ nhóm bắt giữ nào.
Ry-

Tôi nghĩ đó là JavaScript chứ không phải là tên khung.
mr5

20

Hồng ngọc

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

1
Regex của bạn sẽ thất bại, bạn cần sử dụng %r{"(https?://[^"]+)"}. Ngoài ra, bạn có thể sử dụng Net::HTTP.get('www.stroustrup.com', '/C++.html')để rút ngắn yêu cầu (và giữ cho nó có thể đọc được). Vì vậy, toàn bộ mã có thể nằm trong một dòng (giữ cho nó có thể đọc được) : puts Net::HTTP.get("www.stroustrup.com", "/C++.html").scan(%r{"(https?://[^"]+)"}). Chạy nó với ruby -rnet/httpvà bạn thậm chí không cần require 'net/http'dòng.
Hauleth

20

Haskell

Một số rắc rối với "\w"trong 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

Tại sao các loại resultđược chỉ định rõ ràng? Nó nên được hoàn toàn hạn chế bởi việc sử dụng nó trong unlines.
John Dvorak

1
Điều này không kéo dài các quy tắc một chút, nhìn thấy như không phải Network.HTTPvà cũng không TextRegex.Posixcó trong basegói. (Mặc dù chúng ở trong Nền tảng Haskell, và tất nhiên là trên Hackage, vì vậy ...)
đã ngừng quay ngược lại vào

1
@JanDvorak, tôi bắt đầu viết bằng ghci (có lẽ tôi nên đăng nó không thay đổi). Nhưng lưu ý của bạn là có liên quan, cảm ơn.
vlastachu

@leftaroundabout, không biết. Có vẻ như tôi không thể làm được, nếu đã sử dụng gói cơ sở.
vlastachu

networkkhông phải trong basemột trong hai, vì vậy tiết kiệm cho việc cuộn các ràng buộc ổ cắm của riêng bạn không có cách nào thực tế để làm điều đó chỉ với base.
Tiên nữ Lambda

18

PHP

Theo như tôi có thể nói, hầu hết các bản cài đặt PHP hiện đại đều đi kèm với xử lý DOM, vì vậy đây là một bản cài đặt thực sự vượt qua các neo trong 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;
    }
}

Vòng lặp bên trong có thể được rút ngắn thành:

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

Thực sự muốn đưa ra w này (như câu trả lời đầu tiên của tôi ở đây). Bạn đã làm điều đó trước tiên, vì vậy đây là +1 của bạn (vì không sử dụng Regex dễ bị lỗi)! Gợi ý: Bạn có thể sử dụng một què 1thay vì truecho in_arraytìm kiếm nghiêm ngặt. Bạn cũng có thể bỏ qua dấu ngoặc. Tôi không hoàn toàn chắc chắn, nhưng tôi cũng có thể bỏ httpvà chỉ rời khỏi ://(đi theo sơ đồ). .
kaiser

Và: Một khả năng khác sẽ là bỏ đi sự if ( ) {}ủng hộ in_array() and print $url.PHP_EOL. Nhưng vâng, bạn sẽ nhận được +1 (nếu tôi có thể) để dễ đọc nhất :)
kaiser

Chỉ cần thử ví dụ của bạn và gặp lỗi về các tiêu chuẩn nghiêm ngặt (PHP 5.4). Có vẻ như trong nguồn, ở đâu đó có một liên kết bị hỏng hoặc được định dạng sai với dấu chấm phẩy bị thiếu. Bạn có thể tắt báo cáo lỗi bằng cách sử dụng @\DOMDocument. Chỉ cần thử điều đó và có thể xác nhận nó hoạt động.
kaiser

Không, đó là tài liệu sai; về mặt kỹ thuật, bạn không cần phải gọi ::loadHTMLFile()tĩnh và @chỉ thêm ẩn vật phẩm đó.
Jack

2
Đây chắc chắn là một trong những giải pháp "chính xác" nhất, một trong những giải pháp duy nhất tôi có thể thấy được sử dụng trong sản xuất. công việc tốt
Jordon Biondo

14

Vỏ Unix

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

Mặc dù tôi phải thừa nhận điều này không hoạt động nếu có nhiều hơn một liên kết trên một dòng.


1
curl http://www.stroustrup.com/C++.htmllưu một vài ký tự
l0b0

7
"nhưng không cho phép thư viện của bên thứ ba" . Tôi đoán vì wgetlà GNU (như bash), bạn có thể lập luận rằng đó không phải là bên thứ ba. Nhưng curlchắc chắn là bên thứ ba.
Chấn thương kỹ thuật số

Còn về ftp://ftp.research.att.com/pub/c++std/WP/CD2https://www.youtube.com/watch?v=jDqQudbtuqo&feature=youtu.be?
Tobias Kienzler

4
@TobiasKienzler Tôi đoán mã gốc của Stroustrup cũng không tìm thấy chúng
Ruslan

14

Java

import java.util.regex.*;
class M{
    public static void main(String[]v)throws Throwable{
        Matcher m = Pattern.compile( "\"((http)s?://.*?)\"" )
            .matcher(
                 new Scanner(
                         new URL( "http://www.stroustrup.com/C++.html" )
                             .openStream(),
                         "UTF-8")
                     .useDelimiter("\\A")
                     .next());
        while(m.find())
            System.out.println(m.group());
    }
}

3
Bạn có thể định dạng đúng mã trong câu trả lời của bạn? Nó không phải là cạnh tranh cho mã ít đọc nhất. Bạn có thể định dạng nó để tránh các thanh cuộn ngang ít nhất.
Athari

Nếu bạn sử dụng, Scannerbạn có thể làm cho nó xử lý mẫu biểu thức chính quy cho các liên kết trực tiếp và lặp lại qua Scannerkết quả của.
Holger

5
Đúng .. đó là java cho bạn. Sử dụng nó cho mã golf là một cam kết dũng cảm.
javadba

4
Không bao giờ nghĩ rằng tôi thấy một giải pháp java thực sự ngắn hơn C ++!
slebetman

2
Sửa lỗi cho nhận xét cuối cùng của tôi: Tôi phải thừa nhận đây là đoạn mã ngắn nhất và sạch nhất có thể được viết bằng Java. Tôi đã thử một cách tiếp cận trình phân tích cú pháp SAX, có thể được thực hiện thậm chí ngắn hơn với lambdas, nhưng trang web không phải là XHTML và trình phân tích cú pháp đưa ra các ngoại lệ. Regex là cách duy nhất để đi.
Smith

11

Groovy

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

Có thể được cải thiện bằng cách sử dụng? Toán tử để tránh NPE?
Chris K

2
@ChrisK Vitaminki và là người đầu tiên (bên cạnh Bjarne) quanh đây để kiểm tra lỗi? không bao giờ! bên cạnh đó: tôi chỉ thấy các ngoại lệ liên quan đến IO ở đây. Bạn thấy NPE ở đâu?
cfrick

find ALL () có thể trả về null, không? Hay nó sẽ trả về một danh sách trống? Vẫn còn một chút mới mẻ với Groovy. EDIT: nm, có vẻ như findAll () trả về một danh sách trống. Những người Groovy đó rất thông minh. :-)
Chris K

11

SQL (SQL ở mọi nơi 16)

Xác định thủ tục được lưu trữ để tìm nạp trang web

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

Tạo tập kết quả bằng một truy vấn duy nhất

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;

Hạn chế: Điều này tạo ra tới 256 liên kết. Nếu có nhiều liên kết tồn tại, sau đó tăng 256 đến một giá trị thích hợp.


2
Tôi đã không tin rằng sẽ có golf trong SQL ... cho đến bây giờ.
vaxquis

Tôi hiểu rồi ... "liên kết". :-)
Jack tại 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
Tôi đoán đây là CoffeeScript / Node? Tôi đoán bạn nên xác định rằng ...
John Dvorak

Ồ Điều đó rất dễ đọc.
slebetman

@slebetman nó chắc chắn là nhỏ mặc dù
John Dvorak

@slebetman Yeah CoffeeScript dễ đọc hơn JavaScript :) Tôi rất vui khi thoát khỏi tất cả các dấu ngoặc nhọn} :)
RobAu

9

Perl

use LWP;
use feature 'say';

my $agent = new LWP::UserAgent();
my $response = $agent->get('http://www.stroustrup.com/C++.html');

say for $response->content =~ m<"(https?://.+?)">g;

1
Mã sẽ rõ ràng hơn nếu bạn tránh các biến phân tách trường và phân tách bản ghi và chỉ cần thực hiện: in map {"$ _ \ n"} $ answer-> content = ~ m <"(https ?: //.+ ?) "> g;
Daniel Ruoso

@DanielRuoso đồng ý.
Primo

hoặc thậm chí use v5.10;say for $response->content...
Mark Reed

Đối với mỗi anh ấy, tôi cho rằng. Một số tính năng perl6 được backport đã gặp sự cố (kết hợp thông minh, tôi đang nhìn bạn), nhưng saykhá hữu ích, và trong tâm trí tôi rõ ràng hơn ở đây. (Ngoài ra, đã có khá nhiều cải tiến hoàn toàn không liên quan đến perl6ism đối với perl5 trong 13 năm qua; có thể đáng để kiểm tra.)
Mark Reed

@MarkReed Tôi đồng ý rằng saycó lẽ dễ đọc hơn trong trường hợp này, đặc biệt đối với những người ít quen thuộc với perl.
Primo

9

R

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

... mặc dù R được viết chủ yếu bằng C ... nên có lẽ một vài dòng mã C đằng sau 2 dòng mã R đó.


2
Điều đó (hoặc một cái gì đó tương tự) là đúng cho hầu hết các câu trả lời ở đây.
JLRishe

8

Mục tiêu-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
Gì? Hãy viết phiên bản Swift. Cái khung vuông vô nghĩa đó đang làm tổn thương đôi mắt của tôi :)
Ông Smith

2
Chiến thắng cho []! Ngoài ra, chúng ta hoàn toàn nên thêm một phiên bản Smalltalk;)
Bersaelor

@MisterSmith Swift trả lời ngay bây giờ có sẵn ở đây .
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]

Bạn có thể thoát khỏi bằng cách thực hiện http :: dữ liệu bên trong các lệnh. Không cần phải tạo một biến tạm thời. Và tôi cũng định dạng nó bằng cách đặt dòng mới và thụt lề mỗi [. Nhưng đó là một sự lựa chọn phong cách.
slebetman

7

Đi

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 mã này đọc toàn bộ nguồn vào bộ nhớ, vì vậy hãy cân nhắc sử dụng regexp.FindReaderIndexđể tìm kiếm trong luồng, điều đó sẽ giúp ứng dụng chống đạn.


6

Camam

CJam không có regex nên tôi phải sử dụng một cách tiếp cận khác trong cách này:

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

Trước tiên tôi chuyển đổi tất cả 'thành ", sau đó tôi tách tất cả ", lấy mọi chuỗi thay thế và cuối cùng là lọc danh sách đó cho các chuỗi bắt đầu bằng http://hoặc https://. Sau đó, chỉ cần in từng chuỗi được lọc trên một dòng mới.

Hãy thử nó bằng trình thông dịch Java như

java -jar cjam-0.6.2.jar file.cjam

trong đó file.cjam có nội dung của đoạn mã trên.


9
Không biết về phần có thể đọc được ... không biết Cjam có chức năng web
Def

Nếu bạn muốn chơi golf nó ... ''/'"f/:+cho ''/'"*'"/'"f/0f=.
jimmy23013

... Đợi tại sao '"f/0f=có? Đó có phải là để làm một cái gì đó ( 2%ví dụ)?
jimmy23013

6

ĐỤ#

Mã này có thể ngắn hơn nhiều nhưng tôi sẽ viết một cái gì đó như thế này nếu tôi dự kiến ​​sẽ phải đọc hoặc sử dụng lại mã này để nó có nhiều chú thích loại không cần thiết. Nó thể hiện việc sử dụng một mô hình hoạt động MatchValue để cho phép mô hình khớp so với tiêu chuẩn loại CLR trận đấu

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)

Chỉnh sửa Tôi đã tạo getLinks chức năng riêng của mình


Tôi thực sự thích cách bạn sử dụng chú thích loại. Tôi nghĩ việc đặt tên các giá trị để mô tả những gì bạn trả về là ổn, nhưng tên của hàm đủ rõ ràng: giá trị getHTML và html, getLinks và giá trị liên kết. Hai dòng cuối có thể là liên kết |> Seq.iter (printfn "% s")
MichalMa

@MichalMa Tôi đồng ý rằng tên của hàm đủ biểu cảm, các biến html và liên kết ở đó vì lý do thực tế: vì vậy có một nơi nào đó để đặt điểm dừng. Tôi đã sử dụng vòng lặp for thay vì List.iter chỉ vì tôi thích cách nó đọc nhiều hơn, mặc dù trong một thay thế tôi có thể đã sử dụng List.iter.
SourceSimian
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.