friend-to-net-web-developers/micro-utilities

GitHub: friend-to-net-web-developers/micro-utilities

一组针对 .NET 10 Web 项目的微型工具集,提供邮箱验证、URI 处理、Unicode 分析等开箱即用的实用功能。

Stars: 0 | Forks: 0

# .NET Web 开发者的微型工具集 ![.NET Test](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/6cd5f257b2131715.svg) ## 状态 - **单元测试:** [最新测试结果](https://github.com/friend-to-net-web-developers/micro-utilities/actions/workflows/dotnet-test-on-pr-net.yml) ## 概述 一组针对 .NET Web 项目的小型、专注的工具集,涵盖邮箱验证与规范化、URI 处理、HTML ID 生成、YouTube URL 助手、变量名转换以及 Unicode 文本分析。 ## 安装 ``` Install-Package FriendToNetWebDevelopers.MicroUtilities ``` ## 从 1.x 版本迁移 2.0.0 版本包含以下破坏性变更: - **`YoutubeThumbnailEnum` 重命名为 `YoutubeThumbnail`** — `Enum` 后缀具有误导性;此类型是智能枚举(类型安全类),而不是 `System.Enum`。 - **`CharacterToken.IsEmailStructural` 重命名为 `IsStructural`** — 旧名称不准确;该字段同时适用于邮箱和 URI 结构字符。 - **`GetVariableName` 和 `GetClassName` 现在会对 null 参数抛出 `ArgumentNullException`** — 之前会静默返回 `string.Empty`。 - **`BuildAbsoluteUrl` 逻辑已修正** — 在 1.x 版本中,包含/排除端口的分支逻辑是反的。如果您之前通过变通方法解决了此 bug,请移除该变通代码。 - **不再支持 .NET 8 和 .NET 9** — 需要 .NET 10。 ## 用法 所有工具都通过静态 `Utilities` 类访问: ``` using FriendToNetWebDevelopers.MicroUtilities; ``` 扩展方法需要额外的 using 语句: ``` using FriendToNetWebDevelopers.MicroUtilities.Extensions; ``` ### 邮箱验证与规范化 通过检查格式、主机名结构和顶级域名(对照 [IANA TLD 列表](https://data.iana.org/TLD/tlds-alpha-by-domain.txt))来验证邮箱地址。国际化域名(IDN)通过 Punycode 规范化得到完全支持。 #### 验证 ``` Utilities.Email.IsValidEmail("user@example.com"); // returns true Utilities.Email.IsValidEmail("foo@bar"); // returns false ``` #### 规范化 (Punycode & Unicode) `TryGetNormalizedValidPunyEmail` 是主要的规范化入口点。它返回地址的 Unicode 和 Punycode 规范形式,以及字符级注释和可疑输入标志。 ``` // Default normalization — applies all strategies: ToLower, Trim, DropTag, DropDot var okay = Utilities.Email.TryGetNormalizedValidPunyEmail( " First.Last+tag@München.de ", out var punyResult, out var annotation); // okay = true // punyResult.Unicode = "firstlast@münchen.de" // punyResult.Punycode = "firstlast@xn--mnchen-3ya.de" // punyResult.IsSuspicious = false // Drop sub-addressing tag only okay = Utilities.Email.TryGetNormalizedValidPunyEmail( "user+tag@example.com", TryGetNormalizedValidEmailStrategyEnum.DropTag, out punyResult, out _); // okay = true // punyResult.Unicode = "user@example.com" // Lowercase and trim only okay = Utilities.Email.TryGetNormalizedValidPunyEmail( " User@Example.com ", TryGetNormalizedValidEmailStrategyEnum.LowerAndTrim, out punyResult, out _); // okay = true // punyResult.Unicode = "user@example.com" // Skip TLD validation — useful for internal/custom domains okay = Utilities.Email.TryGetNormalizedValidPunyEmail( "admin@internal", TryGetNormalizedValidEmailStrategyEnum.All, out punyResult, out _, skipInternalValidation: true); // okay = true // punyResult.Unicode = "admin@internal" ``` 可用的策略标志和预构建组合定义在 `TryGetNormalizedValidEmailStrategyEnum` 中。 ### 地址注释与安全分析 `AddressAnnotator` 提供对邮箱地址和 URI 组件的字符级检查,识别可疑字符(同形字)、Unicode 使用和无效字符。适用于检测钓鱼和欺诈企图。 ``` var email = "tеst@example.com"; // Contains Cyrillic 'е' — a homoglyph of ASCII 'e' var annotation = Utilities.AddressAnnotator.Annotate(email); if (annotation.ContainsSuspiciousChars) { var suspiciousToken = annotation.LocalTokens.First(t => t.IsSuspicious); // suspiciousToken.Char = "е" // suspiciousToken.HomoglyphOf = "e" } // annotation.LocalPart = "tеst" // annotation.Domain = "example.com" // annotation.ContainsUnicode = true // annotation.Mode = InputMode.Email ``` `string`、`Uri` 和 `MailAddress` 上提供了扩展方法: ``` var annotation = "user@example.com".Annotate(InputMode.Email); var uriAnnotation = new Uri("https://user:pass@example.com").AnnotateUserInfo(); ``` ### URI 工具 #### 构建绝对 URL 从 URI 构建绝对 URL 字符串,根据应用程序是否在调试模式下运行,自动包含或排除端口。 ``` var urlString = Utilities.Url.BuildAbsoluteUrl(uri); // Debug / localhost: https://localhost:44328/some-file.jpg (port included) // Production: https://example.com/some-file.jpg (port stripped) ``` #### Slug 生成与验证 Slug 是小写的、连字符分隔的 URL 路径段。有效的 Slug 匹配 `^[a-z0-9]+(?:-[a-z0-9]+)*$`。 ``` // Validation Utilities.Url.IsValidUriSlug("foo-bar"); // true Utilities.Url.IsValidUriSlug("Foo Bar"); // false // Generation Utilities.Url.TryToConvertToSlug("Foo Bar", out var slug); // returns true, slug = "foo-bar" Utilities.Url.TryToConvertToSlug("-", out var slug); // returns false, slug = "" Utilities.Url.TryToConvertToSlug(null, out var slug); // returns false, slug = "" ``` #### 用户名验证 根据 [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986) 验证 userinfo 组件。 ``` Utilities.Url.IsValidUsername("foobar"); // true Utilities.Url.IsValidUsername("foo bar"); // false Utilities.Url.IsValidUsername(null); // false Utilities.Url.IsValidUsername(null, true); // true — null explicitly allowed ``` #### 路径段验证 ``` Utilities.Url.IsValidPathSegment("foo"); // true Utilities.Url.IsValidPathSegment("foo bar"); // false Utilities.Url.IsValidPathSegment(null); // false ``` #### 查询参数名称验证 ``` Utilities.Url.IsValidQueryParameterName("foo_bar"); // true Utilities.Url.IsValidQueryParameterName("foo@bar"); // false ``` #### 从查询对象构建 URL 将 URL 编码的查询字符串附加到基础 URL。接受 `IDictionary`(唯一键)或 `IEnumerable>`(允许重复键,适用于数组式参数,如 `ids[]=1&ids[]=2`)。 ``` var finalUrl = Utilities.Url.BuildUrl("https://api.example.com", queryObject); ``` #### 顶级域名验证 根据 [IANA TLD 列表](https://data.iana.org/TLD/tlds-alpha-by-domain.txt) 验证 URI 主机的 TLD。 ``` Utilities.Url.HasValidTopLevelDomain(new Uri("https://foobar.com")); // true Utilities.Url.HasValidTopLevelDomain(new Uri("https://foobar.web")); // false ``` #### Punycode & IDN 域名规范化 规范化域名并生成其 Punycode 和 Unicode 表示形式。 ``` Utilities.Url.TryNormalizeAndPunycodeDomain("παράδειγμα.ελ", out var puny, out var uni); // puny = "xn--hxajbheg2az3al.xn--qxam" // uni = "παράδειγμα.ελ" Utilities.Url.TryNormalizeAndPunycodeDomain(" .EXAMPLE.com. ", out puny, out uni); // puny = "example.com" // uni = "example.com" ``` ### ID 工具 生成、验证并强制转换有效的 HTML `id` 属性值。当页面上的多个动态元素(手风琴、滑块、选项卡)需要相互引用的稳定、唯一 ID 时非常有用。 #### 生成 前缀是必需的(默认为 `"id"`)。也可以提供可选的后缀。支持的基本类型:`Guid`、`int`、`uint`、`long`、`ulong`。 ``` // From a new Guid — returns e.g. "id02bfd4e04f0b43f9bf407d3162db9289" Utilities.Id.GetValidHtmlId(); // From a numeric value with custom prefix and suffix Utilities.Id.GetValidHtmlId(4444, "foo_", "_bar"); // returns "foo_4444_bar" ``` #### 验证 ``` Utilities.Id.IsValidId(null); // false Utilities.Id.IsValidId("bob dole"); // false Utilities.Id.IsValidId("bob_dole"); // true ``` 单字母 ID 是有效的: ``` Utilities.Id.IsValidId("a"); // true ``` #### 带回退的强制转换 当输入无效时,使用回退策略返回保证非 null 的字符串: ``` Utilities.Id.TryGetAsValidId( "bob dole", TryGetValidIdDefaultStrategyEnum.EmptyOnInvalid, out var result); // returns false, result = "" Utilities.Id.TryGetAsValidId( "foo bar", TryGetValidIdDefaultStrategyEnum.GenerateOnInvalid, out result); // returns false, result = generated id from GetValidHtmlId() Utilities.Id.TryGetAsValidId( "foo_bar_baz", TryGetValidIdDefaultStrategyEnum.GenerateOnInvalid, out result); // returns true, result = "foo_bar_baz" ``` ### YouTube 工具 #### ID 验证 检查字符串是否为有效的 YouTube 视频 ID —— 正好 11 个字符且匹配 `^[a-zA-Z0-9_-]{11}$`。 ``` Utilities.Youtube.IsValidYoutubeId("SrN4A9rVXj0"); // true Utilities.Youtube.IsValidYoutubeId("foo-bar"); // false ``` #### 缩略图 URL ``` // HQ default thumbnail (always available) Utilities.Youtube.GetYoutubeThumbnail("SrN4A9rVXj0"); // returns "https://i.ytimg.com/vi/SrN4A9rVXj0/hqdefault.jpg" // Max resolution thumbnail (may not be available for all videos) Utilities.Youtube.GetYoutubeThumbnail("SrN4A9rVXj0", YoutubeThumbnail.MaxResDefault); // returns "https://i.ytimg.com/vi/SrN4A9rVXj0/maxresdefault.jpg" // Invalid ID throws Utilities.Youtube.GetYoutubeThumbnail("foo-bar", YoutubeThumbnail.MaxResDefault); // throws BadYoutubeIdException ``` #### 嵌入 URL ``` Utilities.Youtube.GetYoutubeIframeUrl("SrN4A9rVXj0"); // returns "https://www.youtube.com/embed/SrN4A9rVXj0" Utilities.Youtube.GetYoutubeIframeUrl("foo-bar"); // throws BadYoutubeIdException ``` ### 变量与类命名工具 跨命名约定识别、转换和生成变量名及类名。 支持的约定:`CamelCase`、`PascalCase`、`SnakeCase`、`ScreamingSnakeCase`、`KebabCase`、`TrainCase`、`Unicase`、`TrollCase`、`TitleWords`、`SentenceWords`。 #### 格式检测 ``` Utilities.Variable.GetVariableFormat("snake_case_example"); // returns ResultsVariableNameTypeEnum.SnakeCase "camelCase".IsVariableName(ResultsVariableNameTypeEnum.CamelCase); // returns true ``` #### 转换 ``` Utilities.Variable.ConvertToPascalCase("hello-world").result; // returns "HelloWorld" "This is a test".ConvertTo(RequestedVariableNameTypeEnum.CamelCase).result; // returns "thisIsATest" Utilities.Variable.ConvertToTitleWords("a tale of two cities").result; // returns "A Tale of Two Cities" Utilities.Variable.ConvertToSentenceWords("snake_case_variable").result; // returns "Snake case variable" ``` #### 从反射元数据命名 ``` var myInstance = new MyCustomClass(); myInstance.ToVariableName(); // returns "myCustomClass" typeof(MyCustomClass).ToClassName(); // returns "MyCustomClass" typeof(List).ToVariableName(); // returns "list" (generic arity suffix stripped) ``` ### 文本与 Unicode 工具 字符级分析和 Unicode 安全的编码/解码。正确处理代理项对(补充平面字符,如 emoji)将其作为单个单元。 #### Unicode 转义编码与解码 在 Unicode 字符和 ASCII 兼容的转义序列之间转换(BMP 字符为 `\uXXXX`,补充平面字符为 `\UXXXXXXXX`)。 ``` Utilities.Text.EncodeUnicodeEscapes("A©😀"); // returns "A\u00A9\U0001F600" Utilities.Text.DecodeUnicodeEscapes("A\\u00A9\\U0001F600"); // returns "A©😀" // Extension methods "A©😀".ToUnicodeEscapedAscii(); "A\\u00A9\\U0001F600".ToUnicodeDecoded(); ``` #### 文本字符注释 逐个字符对字符串进行分词,将每个字符分类为 `Letter`、`Digit`、`Whitespace`、`Special` 或 `Unicode`,并附带码点和转义序列元数据。 ``` var tokens = "A 😀 1".Annotate().ToList(); // tokens[0]: "A", Type: Letter, Index: 0 // tokens[1]: " ", Type: Whitespace, Index: 1 // tokens[2]: "😀", Type: Unicode, Index: 2, CodePoint: 0x1F600, UnicodeEscape: "\U0001F600" // tokens[3]: " ", Type: Whitespace, Index: 4 (index advanced past surrogate pair) // tokens[4]: "1", Type: Digit, Index: 5 ``` ## 注意事项与兼容性 ### .NET 版本支持 此库仅针对 **.NET 10**。不支持早期版本。 ### 线程安全 所有工具方法都是静态且无状态的。该库是线程安全的。 ### 性能 重用正则表达式的路径使用 `[GeneratedRegex]` 进行编译时源生成。`TitleCaseMinorWords` 查找使用 `HashSet` 实现 O(1) 访问。 ### TLD 更新 `HasValidTopLevelDomain` 和 `IsValidEmail` 根据库中捆绑的 IANA TLD 列表进行验证。此列表会随新版本定期更新。
标签:DNS解析, HTML ID 生成, IDN 支持, NuGet 包, Punycode, SOC Prime, Unicode 文本分析, URI 处理, URL 生成, Web 开发, YouTube URL 解析, 单元测试, 变量名转换, 后端开发, 字符串处理, 实用程序, 工具库, 开发工具, 开源项目, 扩展方法, 数据清洗, 格式验证, 电子邮件验证, 静态方法