web-dev-qa-db-ja.com

必要に応じてURLにスキームを追加

文字列からUriを作成するには、次のようにします。

Uri u = new Uri("example.com");

ただし、問題は、文字列(上記のような)にプロトコルが含まれていない場合、例外が発生することです: "Invalid URI: The format of the URI could not be determined. "

例外を回避するには、次のようなプロトコルを含む文字列を保護する必要があります。

Uri u = new Uri("http://example.com");

しかし、入力としてURLを使用する場合、欠落しているプロトコルをどのように追加できますか?
IndexOf/Substringの操作とは別の意味ですか?

エレガントで高速なものですか?

62
Max Favilli

UriBuilder を使用することもできます。

public static Uri GetUri(this string s)
{
    return new UriBuilder(s).Uri;
}

MSDNからのコメント:

このコンストラクターは、UriBuilderクラスの新しいインスタンスを、uriで指定されたように設定されたFragment、Host、Path、Port、Query、Scheme、およびUriプロパティで初期化します。

uriがスキームを指定しない場合、スキームはデフォルトで「http:」になります。

125
as-cii

URLを検証せずにスキームを追加するだけの場合、最速/最も簡単な方法は、文字列検索を使用することです。例:

string url = "mydomain.com";
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) url = "http://" + url;

より良い方法は、 Uri を使用して TryCreate メソッドを使用してURLを検証することです。

string url = "mydomain.com";
Uri uri;
if ((Uri.TryCreate(url, UriKind.Absolute, out uri) || Uri.TryCreate("http://" + url, UriKind.Absolute, out uri)) &&
    (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
    // Use validated URI here
}

@JanDavidNarkiewiczがコメントで指摘したように、Schemeの検証は、スキームなしでポートが指定されている場合に無効なスキームを防ぐために必要です。 mydomain.com:80

7
Ronald

私の解決策は、プロトコルが正規表現であることを確認するためのプロトコールレスURLです:

Regex.Replace(s, @"^\/\/", "http://");
3
John

Localhost:8800などのようなものを入力するための従来の許可がある特定のケースがありました。つまり、それを解析する必要がありました。 URIを非常に大まかに指定する可能性を分離するもう少し手の込んだParseUriメソッドを構築しましたが、人々が非標準のスキーム(およびIPロング表記のホストも指定する場合もあるため)を指定する時間もキャッチしました

UriBuilderと同様に、何も指定されていない場合、デフォルトでhttpスキームが使用されます。基本認証が指定され、パスワードが数字のみで構成されている場合、問題が発生します。 (そのコミュニティを修正してください)

        private static Uri ParseUri(string uri)
        {

            if (uri.StartsWith("//"))
                return new Uri("http:" + uri);
            if (uri.StartsWith("://"))
                return new Uri("http" + uri);

            var m = System.Text.RegularExpressions.Regex.Match(uri, @"^([^\/]+):(\d+)(\/*)", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
            if (m.Success)
            {
                var port = int.Parse(m.Groups[2].Value);
                if (port <= 65535) //part2 is a port (65535 highest port number)
                    return new Uri("http://" + uri);
                else if (port >= 16777217) //part2 is an ip long (16777217 first ip in long notation)
                    return new UriBuilder(uri).Uri;
                else
                    throw new ArgumentOutOfRangeException("Invalid port or ip long, technically could be local network hostname, but someone needs to be hit on the head for that one");
            }
            else
                return new Uri(uri);
        }
0
Peter