なるだけシンプルにかつそれなりにちゃんと URL が抽出できる正規表現

できるだけシンプルに。
[:space:] は正規表現エンジンの実装にあわせて全角スペースが含まれる奴に置き換えてください。

```rb:extract_url.rb
#!/usr/bin/env ruby
# -*- encoding: utf-8 -*-

URL_REGEXP = /((https?):\/\/(([^[:space:].\/]+\.)+[a-z]+)(\/[^[:space:]]*)?)/i

prefixes = ['', 'hoge', 'hoge ', 'ほげ　', '(']
suffixes = ['', ' fuga', ' fuga', '　ふが', ')']
patterns = [
  {url: 'http://example.com', scheme: 'http', domain: 'example.com', path: nil},
  {url: 'https://example.com', scheme: 'https', domain: 'example.com', path: nil},
  {url: 'http://example.com/', scheme: 'http', domain: 'example.com', path: '/'},
  {url: 'http://example.com/path/to/resource', scheme: 'http', domain: 'example.com', path: '/path/to/resource'},
  {url: 'http://example.com/index.html?foo=bar', scheme: 'http', domain: 'example.com', path: '/index.html?foo=bar'},
  {url: 'http://豊崎愛生.jp', scheme: 'http', domain: '豊崎愛生.jp', path: nil},
  {url: 'http://love.豊崎愛生.jp', scheme: 'http', domain: 'love.豊崎愛生.jp', path: nil},
  {url: 'http://love.豊崎愛生.jp/', scheme: 'http', domain: 'love.豊崎愛生.jp', path: '/'},
  {url: 'http://love.豊崎愛生.ジェーピー', unmatch: true},
  {url: 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)', scheme: 'http', domain: 'ja.wikipedia.org', path: '/wiki/LISP_(声優ユニット)'},
]

prefixes.each do |prefix|
  suffixes.each do |suffix| 
    patterns.each do |pattern|
      test = "#{prefix}#{pattern[:url]}#{suffix}"
      ret = URL_REGEXP =~ test
      if !pattern[:unmatch] && ret
        {url: $1, scheme: $2, domain: $3, path: $5}.each do |k, v|
          s = pattern[k]
          puts "fail: [#{k}] '#{s}' -> '#{v}'" unless s == v
        end
      end
    end
  end
end
```

## 上のテストを走らせた時に失敗するパターン

```text:out.txt
fail: [url] 'http://example.com/' -> 'http://example.com/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://example.com/path/to/resource' -> 'http://example.com/path/to/resource)'
fail: [path] '/path/to/resource' -> '/path/to/resource)'
fail: [url] 'http://example.com/index.html?foo=bar' -> 'http://example.com/index.html?foo=bar)'
fail: [path] '/index.html?foo=bar' -> '/index.html?foo=bar)'
fail: [url] 'http://love.豊崎愛生.jp/' -> 'http://love.豊崎愛生.jp/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)' -> 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット))'
fail: [path] '/wiki/LISP_(声優ユニット)' -> '/wiki/LISP_(声優ユニット))'
fail: [url] 'http://example.com/' -> 'http://example.com/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://example.com/path/to/resource' -> 'http://example.com/path/to/resource)'
fail: [path] '/path/to/resource' -> '/path/to/resource)'
fail: [url] 'http://example.com/index.html?foo=bar' -> 'http://example.com/index.html?foo=bar)'
fail: [path] '/index.html?foo=bar' -> '/index.html?foo=bar)'
fail: [url] 'http://love.豊崎愛生.jp/' -> 'http://love.豊崎愛生.jp/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)' -> 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット))'
fail: [path] '/wiki/LISP_(声優ユニット)' -> '/wiki/LISP_(声優ユニット))'
fail: [url] 'http://example.com/' -> 'http://example.com/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://example.com/path/to/resource' -> 'http://example.com/path/to/resource)'
fail: [path] '/path/to/resource' -> '/path/to/resource)'
fail: [url] 'http://example.com/index.html?foo=bar' -> 'http://example.com/index.html?foo=bar)'
fail: [path] '/index.html?foo=bar' -> '/index.html?foo=bar)'
fail: [url] 'http://love.豊崎愛生.jp/' -> 'http://love.豊崎愛生.jp/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)' -> 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット))'
fail: [path] '/wiki/LISP_(声優ユニット)' -> '/wiki/LISP_(声優ユニット))'
fail: [url] 'http://example.com/' -> 'http://example.com/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://example.com/path/to/resource' -> 'http://example.com/path/to/resource)'
fail: [path] '/path/to/resource' -> '/path/to/resource)'
fail: [url] 'http://example.com/index.html?foo=bar' -> 'http://example.com/index.html?foo=bar)'
fail: [path] '/index.html?foo=bar' -> '/index.html?foo=bar)'
fail: [url] 'http://love.豊崎愛生.jp/' -> 'http://love.豊崎愛生.jp/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)' -> 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット))'
fail: [path] '/wiki/LISP_(声優ユニット)' -> '/wiki/LISP_(声優ユニット))'
fail: [url] 'http://example.com/' -> 'http://example.com/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://example.com/path/to/resource' -> 'http://example.com/path/to/resource)'
fail: [path] '/path/to/resource' -> '/path/to/resource)'
fail: [url] 'http://example.com/index.html?foo=bar' -> 'http://example.com/index.html?foo=bar)'
fail: [path] '/index.html?foo=bar' -> '/index.html?foo=bar)'
fail: [url] 'http://love.豊崎愛生.jp/' -> 'http://love.豊崎愛生.jp/)'
fail: [path] '/' -> '/)'
fail: [url] 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット)' -> 'http://ja.wikipedia.org/wiki/LISP_(声優ユニット))'
fail: [path] '/wiki/LISP_(声優ユニット)' -> '/wiki/LISP_(声優ユニット))'
```

(http://ja.wikipedia.org/wiki/LISP_(声優ユニット))
(http://ja.wikipedia.org/wiki/LISP_(声優ユニット)}
(http://ja.wikipedia.org/wiki/LISP_(声優ユニット)))

(http://example.com/path/to/resource) みたいなことされるとどうしようもないので path の部分を (\/[^[:space:]\(\)]*)? とかにするといけるようになりますが /wiki/LISP_(声優ユニット) とかがおかしくなります。
それも回避したい人はもっとがんばってください。