URL の一部の取得 (正規表現)
-
09-06-2019 - |
質問
URL を指定すると (単一行):
http://test.example.com/dir/subdir/file.html
正規表現を使用して次の部分を抽出するにはどうすればよいですか。
- サブドメイン (テスト)
- ドメイン (example.com)
- ファイルを含まないパス (/dir/subdir/)
- ファイル (file.html)
- ファイルのあるパス (/dir/subdir/file.html)
- パスのない URL (http://test.example.com)
- (他に役立つと思われるものがあれば追加します)
次の URL を入力しても、正規表現は正しく機能するはずです。
http://example.example.com/example/example/example.html
解決
クエリパラメーターやアンカーを含む完全なURLを解析して分割する単一の正規表現
https://www.google.com/dir/1/2/search.html?arg=0-a&arg1=1-b&arg3-c#hash
^((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$
RexEx のポジション:
URL:RegExp['$&']、
プロトコル:RegExp.$2、
ホスト:RegExp.$3、
パス:RegExp.$4、
ファイル:RegExp.$6、
クエリ: RegExp.$7、
ハッシュ:RegExp.$8
その後、ホスト ('.' で区切られた) をさらに簡単に解析できます。
何 私 次のようなものを使用します:
/*
^(.*:)//([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$
*/
proto $1
host $2
port $3
the-rest $4
さらに「残り」をできるだけ具体的に解析します。それを 1 つの正規表現で行うのは、ちょっとクレイジーです。
他のヒント
パーティーに遅れてしまったことはわかっていますが、正規表現を使わずにブラウザに URL を解析させる簡単な方法があります。
var a = document.createElement('a');
a.href = 'http://www.example.com:123/foo/bar.html?fox=trot#foo';
['href','protocol','host','hostname','port','pathname','search','hash'].forEach(function(k) {
console.log(k+':', a[k]);
});
/*//Output:
href: http://www.example.com:123/foo/bar.html?fox=trot#foo
protocol: http:
host: www.example.com:123
hostname: www.example.com
port: 123
pathname: /foo/bar.html
search: ?fox=trot
hash: #foo
*/
私はパーティーに数年遅れていますが、Uniform Resource Identifier 仕様に 正規表現を使用した URI の解析に関するセクション. 。Berners-Lee らが作成した正規表現は次のとおりです。
^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9
上の 2 行目の数字は、読みやすくするためだけのものです。それらは、各サブエクスペッションの基準点を示します(すなわち、各ペアの括弧)。サブエクスペッションの一致した値を$と呼びます。たとえば、上記の式を次のように照合すると、
http://www.ics.uci.edu/pub/ietf/uri/#Related
結果は次の部分式と一致します。
$1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 = <undefined> $7 = <undefined> $8 = #Related $9 = Related
実は、JavaScript ではスラッシュをエスケープする必要があることがわかりました。
^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
最も投票数が多かった回答(hometoast の回答)が私にとって完全には機能しないことがわかりました。2 つの問題:
- ポート番号は扱えません。
- ハッシュ部分が壊れています。
以下は修正版です。
^((http[s]?|ftp):\/)?\/?([^:\/\s]+)(:([^\/]*))?((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?$
パーツの位置は以下の通りです。
int SCHEMA = 2, DOMAIN = 3, PORT = 5, PATH = 6, FILE = 8, QUERYSTRING = 9, HASH = 12
anon ユーザーによって投稿された編集:
function getFileName(path) {
return path.match(/^((http[s]?|ftp):\/)?\/?([^:\/\s]+)(:([^\/]*))?((\/[\w\/-]+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?$/i)[8];
}
すべての URL に一致する正規表現が必要だったので、これを作成しました。
/(?:([^\:]*)\:\/\/)?(?:([^\:\@]*)(?:\:([^\@]*))?\@)?(?:([^\/\:]*)\.(?=[^\.\/\:]*\.[^\.\/\:]*))?([^\.\/\:]*)(?:\.([^\/\.\:]*))?(?:\:([0-9]*))?(\/[^\?#]*(?=.*?\/)\/)?([^\?#]*)?(?:\?([^#]*))?(?:#(.*))?/
すべての URL、あらゆるプロトコル、さらには次のような URL に一致します。
ftp://user:pass@www.cs.server.com:8080/dir1/dir2/file.php?param1=value1#hashtag
結果 (JavaScript で) は次のようになります。
["ftp", "user", "pass", "www.cs", "server", "com", "8080", "/dir1/dir2/", "file.php", "param1=value1", "hashtag"]
のような URL
mailto://admin@www.cs.server.com
次のようになります:
["mailto", "admin", undefined, "www.cs", "server", "com", undefined, undefined, undefined, undefined, undefined]
私はこれをJavaScriptで解決しようとしていました。これは次のように処理される必要があります。
var url = new URL('http://a:b@example.com:890/path/wah@t/foo.js?foo=bar&bingobang=&king=kong@kong.com#foobar/bing/bo@ng?bang');
(少なくとも Chrome では) 次のように解析されるためです。
{
"hash": "#foobar/bing/bo@ng?bang",
"search": "?foo=bar&bingobang=&king=kong@kong.com",
"pathname": "/path/wah@t/foo.js",
"port": "890",
"hostname": "example.com",
"host": "example.com:890",
"password": "b",
"username": "a",
"protocol": "http:",
"origin": "http://example.com:890",
"href": "http://a:b@example.com:890/path/wah@t/foo.js?foo=bar&bingobang=&king=kong@kong.com#foobar/bing/bo@ng?bang"
}
ただし、これはクロスブラウザではありません (https://developer.mozilla.org/en-US/docs/Web/API/URL)、これを組み合わせて、上記と同じ部分を取り出しました。
^(?:(?:(([^:\/#\?]+:)?(?:(?:\/\/)(?:(?:(?:([^:@\/#\?]+)(?:\:([^:@\/#\?]*))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((?:\/?(?:[^\/\?#]+\/+)*)(?:[^\?#]*)))?(\?[^#]+)?)(#.*)?
この正規表現の功績は次のとおりです。 https://gist.github.com/rpflorence このjsperfを投稿した人 http://jsperf.com/url-parsing (元々はここにありました: https://gist.github.com/jlong/2428561#comment-310066)この正規表現の元になった正規表現を考案したのは誰です。
パーツは次の順序で配置されます。
var keys = [
"href", // http://user:pass@host.com:81/directory/file.ext?query=1#anchor
"origin", // http://user:pass@host.com:81
"protocol", // http:
"username", // user
"password", // pass
"host", // host.com:81
"hostname", // host.com
"port", // 81
"pathname", // /directory/file.ext
"search", // ?query=1
"hash" // #anchor
];
それをラップしてクエリパラメータを提供する小さなライブラリもあります。
https://github.com/sadams/lite-url (バウアーでもご利用いただけます)
改善点がある場合は、より多くのテストを含むプルリクエストを作成してください。感謝の気持ちを込めて受け入れてマージします。
より読みやすいソリューションを提案します (Python ですが、あらゆる正規表現に適用されます)。
def url_path_to_dict(path):
pattern = (r'^'
r'((?P<schema>.+?)://)?'
r'((?P<user>.+?)(:(?P<password>.*?))?@)?'
r'(?P<host>.*?)'
r'(:(?P<port>\d+?))?'
r'(?P<path>/.*?)?'
r'(?P<query>[?].*?)?'
r'$'
)
regex = re.compile(pattern)
m = regex.match(path)
d = m.groupdict() if m is not None else None
return d
def main():
print url_path_to_dict('http://example.example.com/example/example/example.html')
プリント:
{
'host': 'example.example.com',
'user': None,
'path': '/example/example/example.html',
'query': None,
'password': None,
'port': None,
'schema': 'http'
}
サブドメインとドメインは、トップレベル ドメインと同様に、サブドメインにも複数の部分があるため、難しいです。 http://sub1.sub2.domain.co.uk/
the path without the file : http://[^/]+/((?:[^/]+/)*(?:[^/]+$)?)
the file : http://[^/]+/(?:[^/]+/)*((?:[^/.]+\.)+[^/.]+)$
the path with the file : http://[^/]+/(.*)
the URL without the path : (http://[^/]+/)
(Markdown は正規表現に対してあまりフレンドリーではありません)
この改良されたバージョンは、パーサーと同じくらい確実に動作するはずです。
// Applies to URI, not just URL or URN:
// http://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Relationship_to_URL_and_URN
//
// http://labs.apache.org/webarch/uri/rfc/rfc3986.html#regexp
//
// (?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?
//
// http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax
//
// $@ matches the entire uri
// $1 matches scheme (ftp, http, mailto, mshelp, ymsgr, etc)
// $2 matches authority (host, user:pwd@host, etc)
// $3 matches path
// $4 matches query (http GET REST api, etc)
// $5 matches fragment (html anchor, etc)
//
// Match specific schemes, non-optional authority, disallow white-space so can delimit in text, and allow 'www.' w/o scheme
// Note the schemes must match ^[^\s|:/?#]+(?:\|[^\s|:/?#]+)*$
//
// (?:()(www\.[^\s/?#]+\.[^\s/?#]+)|(schemes)://([^\s/?#]*))([^\s?#]*)(?:\?([^\s#]*))?(#(\S*))?
//
// Validate the authority with an orthogonal RegExp, so the RegExp above won’t fail to match any valid urls.
function uriRegExp( flags, schemes/* = null*/, noSubMatches/* = false*/ )
{
if( !schemes )
schemes = '[^\\s:\/?#]+'
else if( !RegExp( /^[^\s|:\/?#]+(?:\|[^\s|:\/?#]+)*$/ ).test( schemes ) )
throw TypeError( 'expected URI schemes' )
return noSubMatches ? new RegExp( '(?:www\\.[^\\s/?#]+\\.[^\\s/?#]+|' + schemes + '://[^\\s/?#]*)[^\\s?#]*(?:\\?[^\\s#]*)?(?:#\\S*)?', flags ) :
new RegExp( '(?:()(www\\.[^\\s/?#]+\\.[^\\s/?#]+)|(' + schemes + ')://([^\\s/?#]*))([^\\s?#]*)(?:\\?([^\\s#]*))?(?:#(\\S*))?', flags )
}
// http://en.wikipedia.org/wiki/URI_scheme#Official_IANA-registered_schemes
function uriSchemesRegExp()
{
return 'about|callto|ftp|gtalk|http|https|irc|ircs|javascript|mailto|mshelp|sftp|ssh|steam|tel|view-source|ymsgr'
}
次のことを試してください。
^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?
HTTP / FTP、サブドメイン、フォルダー、ファイルなどをサポートします。
簡単なGoogle検索で見つけました。
http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx
/^((?P<scheme>https?|ftp):\/)?\/?((?P<username>.*?)(:(?P<password>.*?)|)@)?(?P<hostname>[^:\/\s]+)(?P<port>:([^\/]*))?(?P<path>(\/\w+)*\/)(?P<filename>[-\w.]+[^#?\s]*)?(?P<query>\?([^#]*))?(?P<fragment>#(.*))?$/
についての私の答えから 同様の質問. 。いくつかのバグ (ユーザー名/パスワードをサポートしていない、単一文字のファイル名をサポートしていない、フラグメント識別子が壊れているなど) があったため、言及されている他のものよりもうまく動作します。
.NET の Uri オブジェクトを使用すると、すべての http/https、ホスト、ポート、パス、およびクエリを取得できます。難しい作業は、ホストをサブドメイン、ドメイン名、TLD に分割することだけです。
これを行うための標準はなく、単に文字列解析や RegEx を使用して正しい結果を生成することはできません。最初は RegEx 関数を使用していますが、すべての URL がサブドメインを正しく解析できるわけではありません。実践的な方法は、TLD のリストを使用することです。URL の TLD が定義されると、左側の部分がドメインになり、残りがサブドメインになります。
ただし、新しい TLD が可能であるため、リストを維持する必要があります。現時点で私が知っているのは、publicsuffix.org が最新のリストを維持しており、Google コードのドメイン名パーサー ツールを使用してパブリック サフィックス リストを解析し、DomainName オブジェクトを使用してサブドメイン、ドメイン、TLD を簡単に取得できるということです。ドメイン名.サブドメイン、ドメイン名.ドメイン、およびドメイン名.TLD。
この回答も役に立ちます:URLからサブドメインを取得する
コールメラン
これは完全で、プロトコルに依存しないものです。
function getServerURL(url) {
var m = url.match("(^(?:(?:.*?)?//)?[^/?#;]*)");
console.log(m[1]) // Remove this
return m[1];
}
getServerURL("http://dev.test.se")
getServerURL("http://dev.test.se/")
getServerURL("//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
getServerURL("//")
getServerURL("www.dev.test.se/sdas/dsads")
getServerURL("www.dev.test.se/")
getServerURL("www.dev.test.se?abc=32")
getServerURL("www.dev.test.se#abc")
getServerURL("//dev.test.se?sads")
getServerURL("http://www.dev.test.se#321")
getServerURL("http://localhost:8080/sads")
getServerURL("https://localhost:8080?sdsa")
プリント
http://dev.test.se
http://dev.test.se
//ajax.googleapis.com
//
www.dev.test.se
www.dev.test.se
www.dev.test.se
www.dev.test.se
//dev.test.se
http://www.dev.test.se
http://localhost:8080
https://localhost:8080
上記のどれも私にとってはうまくいきませんでした。私が最終的に使用したものは次のとおりです。
/^(?:((?:https?|s?ftp):)\/\/)([^:\/\s]+)(?::(\d*))?(?:\/([^\s?#]+)?([?][^?#]*)?(#.*)?)?/
私は「JavaScript:」で公開されている正規表現が好きです。良い部分」。短すぎず、複雑すぎません。github のこのページには、それを使用する JavaScript コードもあります。しかし、それはどんな言語にも適応できます。https://gist.github.com/voodooGQ/4057330
Java はこれを行う URL クラスを提供します。 URL オブジェクトをクエリします。
余談ですが、PHP が提供するのは、 parse_url().
正規表現は使用しないことをお勧めします。次のような API 呼び出し WinHttpCrackUrl() エラーが発生しにくくなります。
http://msdn.microsoft.com/en-us/library/aa384092%28VS.85%29.aspx
私は、私のニーズをカバーできなかったこれらのいくつかを試しました。特に、パスのない URL をキャッチできなかった最も投票数の高いもの (http://example.com/)
また、グループ名がないため、ansible では使用できませんでした (または、私の jinja2 スキルが不足している可能性があります)。
したがって、これは、ソースがここで最も投票されたバージョンでわずかに変更された私のバージョンです。
^((?P<protocol>http[s]?|ftp):\/)?\/?(?P<host>[^:\/\s]+)(?P<path>((\/\w+)*\/)([\w\-\.]+[^#?\s]+))*(.*)?(#[\w\-]+)?$
使用する http://www.fileformat.info/tool/regex.htm hometoast の正規表現はうまく機能します。
しかし、ここで解決策があります。プログラム内のさまざまな状況でさまざまな正規表現パターンを使用したいのです。
たとえば、この URL があり、プログラム内でサポートされているすべての URL をリストする列挙があります。列挙内の各オブジェクトには、URL との比較に使用される正規表現パターンを返すメソッド getRegexPattern があります。特定の正規表現パターンが true を返す場合、この URL がプログラムでサポートされていることがわかります。したがって、各列挙には、URL 内のどこを参照する必要があるかに応じて、独自の正規表現があります。
Hometoast の提案は素晴らしいですが、私の場合は役に立たないと思います (すべての列挙に同じ正規表現をコピーペーストしない限り)。
だからこそ、各状況に個別に正規表現を与える答えが欲しかったのです。ホームトーストには+1ですが。;)
これに関して言語に依存しないと主張しているのはわかりますが、どのような正規表現機能があるかを知るために、何を使用しているのか教えていただけますか?
非キャプチャ一致の機能がある場合は、キャプチャする必要のない部分式が次のように設定されるように hometoast の式を変更できます。
(?:SOMESTUFF)
それでも正規表現をコピーして複数の場所に貼り付ける (そして少し変更する) 必要がありますが、これは理にかなっています。部分式が存在するかどうかを確認するだけではなく、存在するかどうかを確認することになります。 URLの一部として. 。部分式に非キャプチャ修飾子を使用すると、必要なものだけが得られ、それ以上は何も得られません。私の解釈が正しければ、それがあなたが望むものです。
ちょっとしたメモとして、hometoast の式には 1 文字しか含まれていないため、「https」の「s」を括弧で囲む必要はありません。量指定子は、直前の 1 文字 (または文字クラスまたは部分式) を量化します。それで:
https?
「http」または「https」にうまく一致します。
regexp を使用して、ファイルを含まない URL パスを取得します。
URL = 'http://domain/dir1/dir2/somefile'url.scan(/^(http:// [^/]+)((?:/[^/]+)+(?=/))?(?:[^/]+)?$ /i).to_s
この URL への相対パスを追加する場合に便利です。
String s = "https://www.thomas-bayer.com/axis2/services/BLZService?wsdl";
String regex = "(^http.?://)(.*?)([/\\?]{1,})(.*)";
System.out.println("1: " + s.replaceAll(regex, "$1"));
System.out.println("2: " + s.replaceAll(regex, "$2"));
System.out.println("3: " + s.replaceAll(regex, "$3"));
System.out.println("4: " + s.replaceAll(regex, "$4"));
次の出力が提供されます。
1:https://
2:www.thomas-bayer.com
3: /
4:axis2/services/BLZService?wsdl
URLを次のように変更すると、
文字列 s = "https://www.thomas-bayer.com?wsdl=qwerwer&ttt=888";出力は次のようになります。
1:https://
2:www.thomas-bayer.com
3: ?
4:wsdl=qwerwer&ttt=888
楽しむ..
ヨシ・レフ
完全な解析を行うための正規表現は非常に恐ろしいものです。読みやすくするために名前付き後方参照を含め、各部分を別々の行に分割しましたが、それでも次のようになります。
^(?:(?P<protocol>\w+(?=:\/\/))(?::\/\/))?
(?:(?P<host>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::(?P<port>[0-9]+))?)\/)?
(?:(?P<path>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)?
(?P<file>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)
(?:\?(?P<querystring>(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))?
(?:#(?P<fragment>.*))?$
非常に冗長にする必要があるのは、プロトコルまたはポートを除いて、どの部分にも HTML エンティティを含めることができるため、フラグメントの説明が非常に難しくなるということです。したがって、最後のいくつかのケース (ホスト、パス、ファイル、クエリ文字列、フラグメント) では、任意の HTML エンティティまたは文字列以外の文字を許可します。 ?
または #
. 。HTML エンティティの正規表現は次のようになります。
$htmlentity = "&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);"
これを抽出すると (口ひげ構文を使用して表現しました)、もう少し読みやすくなります。
^(?:(?P<protocol>(?:ht|f)tps?|\w+(?=:\/\/))(?::\/\/))?
(?:(?P<host>(?:{{htmlentity}}|[^\/?#:])+(?::(?P<port>[0-9]+))?)\/)?
(?:(?P<path>(?:{{htmlentity}}|[^?#])+)\/)?
(?P<file>(?:{{htmlentity}}|[^?#])+)
(?:\?(?P<querystring>(?:{{htmlentity}};|[^#])+))?
(?:#(?P<fragment>.*))?$
もちろん、JavaScript では名前付き後方参照は使用できないため、正規表現は次のようになります。
^(?:(\w+(?=:\/\/))(?::\/\/))?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::([0-9]+))?)\/)?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)(?:\?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))?(?:#(.*))?$
各試合でのプロトコルは次のとおりです。 \1
, 、ホストは \2
, 、ポートは \3
, 、 パス \4
, 、 ファイル \5
, 、クエリ文字列 \6
, 、およびフラグメント \7
.
//USING REGEX
/**
* Parse URL to get information
*
* @param url the URL string to parse
* @return parsed the URL parsed or null
*/
var UrlParser = function (url) {
"use strict";
var regx = /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
matches = regx.exec(url),
parser = null;
if (null !== matches) {
parser = {
href : matches[0],
withoutHash : matches[1],
url : matches[2],
origin : matches[3],
protocol : matches[4],
protocolseparator : matches[5],
credhost : matches[6],
cred : matches[7],
user : matches[8],
pass : matches[9],
host : matches[10],
hostname : matches[11],
port : matches[12],
pathname : matches[13],
segment1 : matches[14],
segment2 : matches[15],
search : matches[16],
hash : matches[17]
};
}
return parser;
};
var parsedURL=UrlParser(url);
console.log(parsedURL);