從 URL 中提取域名、路徑層級、文件名是常見需求。手寫 IndexOf/Substring 易出錯、難維護。.NET 內建 System.Uri 與 Regex 提供健壯、標準化的解析能力,本文提供開箱即用的三個擴充方法。
public static class UrlExtensions {
/// 取得域名(含連接埠,不含 scheme)
public static string GetDomain(this string url) {
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
return uri.Host; // 自動排除 scheme、path、query
return string.Empty;
}
/// 取得路徑目錄層級陣列(不含檔名)
public static string[] GetDirectories(this string url) {
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return Array.Empty();
// AbsolutePath 以 '/' 開頭,TrimStart 移除首個 '/'
var segments = uri.AbsolutePath.TrimStart('/').Split('/');
// 最後一段若含 '.' 視為檔名,排除
if (segments.Length > 0 && segments[^1].Contains('.'))
return segments[..^1];
return segments;
}
/// 取得檔名(含副檔名)
public static string GetFileName(this string url) {
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
return string.Empty;
var segments = uri.AbsolutePath.TrimStart('/').Split('/');
return segments.Length > 0 && segments[^1].Contains('.') ? segments[^1] : string.Empty;
}
}
public static class UrlRegexParser {
// 命名群組:scheme、host、port、path、file
private static readonly Regex UrlRegex = new(
@"^(?https?)://(?[^:/]+)(?::(?\d+))?(?/[^?#]*)?(?:\?(?[^#]*))?(?:#(?.*))?$",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static string GetDomain(string url) {
var m = UrlRegex.Match(url);
return m.Success ? m.Groups["host"].Value : string.Empty;
}
public static string[] GetDirectories(string url) {
var m = UrlRegex.Match(url);
if (!m.Success) return Array.Empty();
var path = m.Groups["path"].Value.TrimStart('/');
if (string.IsNullOrEmpty(path)) return Array.Empty();
var segs = path.Split('/');
return segs[^1].Contains('.') ? segs[..^1] : segs;
}
public static string GetFileName(string url) {
var m = UrlRegex.Match(url);
if (!m.Success) return string.Empty;
var path = m.Groups["path"].Value.TrimStart('/');
if (string.IsNullOrEmpty(path)) return string.Empty;
var segs = path.Split('/');
return segs[^1].Contains('.') ? segs[^1] : string.Empty;
}
}
var url = "https://api.example.com:8080/v2/users/profile/avatar.png?token=abc#section";
Console.WriteLine($"域名: {url.GetDomain()}"); // api.example.com
Console.WriteLine($"目錄: {string.Join("/", url.GetDirectories())}"); // v2/users/profile
Console.WriteLine($"檔名: {url.GetFileName()}"); // avatar.png
| 輸入 | GetDomain | GetDirectories | GetFileName |
|---|---|---|---|
/static/css/main.css | (空) | static/css | main.css |
https://site.com/dir/ | site.com | dir | (空) |
https://site.com/file?name=val | site.com | (空) | file |
https://site.com/path/file.tar.gz | site.com | path | file.tar.gz |
uri.OriginalString 配合 Regex。api/v1.0/users),實務建議結合 Content-Disposition 標頭或已知副檔名清單。Uri 內部快取,高頻呼叫無額外開銷;Regex 建議 Compiled 選項並靜態快取。優先使用 System.Uri 擴充方法,標準、簡潔、效能佳;僅在非標準 URL 或需複雜群組捕獲時改用 Regex。將上述代碼納入共用類庫,徹底告別手寫字串切割的痛苦。