できるだけシンプルに。
[:space:] は正規表現エンジンの実装にあわせて全角スペースが含まれる奴に置き換えてください。
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
上のテストを走らせた時に失敗するパターン
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_(声優ユニット) とかがおかしくなります。
それも回避したい人はもっとがんばってください。