ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Humanizer ITruncator 接口深度指南:.NET 字符串截断的完整实现原理与实战

Humanizer ITruncator 接口深度指南:.NET 字符串截断的完整实现原理与实战 开发工具【免费下载链接】HumanizerHumanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities项目地址https://gitcode.com/gh_mirrors/hu/Humanizer点击查看免费下载导读ITruncator 是 Humanizer 中负责字符串截断的核心抽象接口它把如何截断、截到什么程度、从哪里截断、用什么符号标记截断这一系列问题统一收敛为一个四参数方法签名。本篇指南以该接口为骨架结合仓库源码、五个内置实现与 TruncatorTests.cs 中的真实测试用例完整讲解接口契约、TruncateFrom 方向枚举、五种截断策略的底层算法差异以及如何通过扩展方法与自定义实现把截断能力接入业务代码。读完你将能够精确区分 FixedLength 与 FixedNumberOfCharacters 的字符口径差异掌握保留完整单词的两种动态策略各自的适用场景并能写出符合 ITruncator 契约的自定义实现。ITruncator 接口契约一个方法统一五种截断语义接口定义位于 ITruncator.cs全文只有一个方法却承担着 Humanizer 全部截断语义的抽象public interface ITruncator { [return: NotNullIfNotNull(nameof(value))] string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom TruncateFrom.Right); }对照 API 文档Humanizer.ITruncator.md中的方法说明四个参数的语义如下参数类型说明valuestring?待截断的字符串允许为 null此时实现应返回 nulllengthint截断后的目标长度不同实现中该长度的口径不同见下文五种策略truncationStringstring?用于标记截断位置的字符串常见为 … 或 ...允许为 null 或空串truncateFromTruncateFrom枚举决定从字符串的哪一端截断默认值为Right方法返回string?即截断后的字符串接口上的[return: NotNullIfNotNull(nameof(value))]特性向调用方与分析器声明只要传入的value非 null返回值就非 null。契约中还隐含一个细节length通常指最终结果的总长度上限truncationString的字符数会占用这个预算——这一点在五种实现中有着截然不同的处理方式。TruncateFrom 枚举截断方向方向参数的类型定义在 TruncateFrom.cs仅两个成员Left从字符串的起始端左侧截断保留尾部内容截断标记拼在最前面Right从字符串的末尾端右侧截断保留开头内容截断标记拼在最后面也是默认值。Left方向在 UI 中常用于保留路径的文件名部分保留日志的结尾部分等需要展示尾部关键信息的场景。内置五种实现Truncator 静态工厂Humanizer 没有让调用方直接 new 具体实现类多数实现类是internal的而是通过 Truncator.cs 这个静态工厂统一暴露五个单例public static class Truncator { public static ITruncator FixedLength { get; } new FixedLengthTruncator(); public static ITruncator FixedNumberOfCharacters { get; } new FixedNumberOfCharactersTruncator(); public static ITruncator FixedNumberOfWords { get; } new FixedNumberOfWordsTruncator(); public static ITruncator DynamicLengthAndPreserveWords { get; } new DynamicLengthAndPreserveWordsTruncator(); public static ITruncator DynamicNumberOfCharactersAndPreserveWords { get; } new DynamicNumberOfCharactersAndPreserveWordsTruncator(); }五个实现覆盖了两种维度计数口径按字符长度 / 按字母数字个数 / 按单词数与是否保留完整单词固定硬切 / 动态回退到词边界。下面逐一拆解其算法与行为差异。1. FixedLengthTruncator按字符总长度硬截断源码见 FixedLengthTruncator.cs逻辑最直白value为 null 返回 null空串或长度不超过length时原样返回若truncationString为 null 或其长度超过length则完全忽略标记直接取value[..length]右侧截断或value[^length..]左侧截断否则按方向拼接右侧截断为value[..(length - truncationString.Length)] truncationString左侧截断为truncationString value[(value.Length - length truncationString.Length)..]。注意它统计的是字符串的LengthUTF-16 代码单元数不区分字母、数字、空白或标点。测试 TruncatorTests.cs 验证了标记过长时的兜底行为Text with delimiter length greater than truncate length truncates to fixed length without truncation string.Truncate(2, ...)输出Te即标记 ... 比预算还长时直接丢弃标记。2. FixedNumberOfCharactersTruncator只数字母与数字源码见 FixedNumberOfCharactersTruncator.cs与 FixedLength 的关键差异在于length只统计字母和数字char.IsLetterOrDigit空格、标点、符号不占预算。算法先正向扫描计数若字母数字总数超过length才截断截断时从两端向中间数到预算位置落刀。这一点在测试中有鲜明对比TruncatorTests.csText with more characters than truncate length.Truncate(10, Truncator.FixedNumberOfCharacters)输出Text with m…——10 个字符中只有字母数字计入所以保留的原文比 FixedLength 的Text long…更长。适合对可见字符密度敏感、希望空格不挤占内容的排版场景。3. FixedNumberOfWordsTruncator按单词数量截断源码见 FixedNumberOfWordsTruncator.cslength的单位是单词个数空白char.IsWhiteSpace是分词符。实现先无分配地扫描统计单词数若超出预算再从对应方向数到第length个单词的边界处拼接标记。测试证明换行、回车、制表符都能正确分词TruncatorTests.csText with more words than truncate length.Truncate(4, Truncator.FixedNumberOfWords) Text with more words… Words are\nsplit\rby\twhitespace.Truncate(4, Truncator.FixedNumberOfWords) Words are\nsplit\rby…注意 FixedNumberOfWords 允许中间某个单词被截断吗不会——它恰好在单词边界落刀因此单词不会残缺但单词内部不含空格的长串会被整体保留可能出现输出超过目标字符预算的情况。这是按词截断与按字符截断天然的口径差异。4. DynamicLengthAndPreserveWordsTruncator字符预算 完整单词源码见 DynamicLengthAndPreserveWordsTruncator.cs它把前两种策略的优点结合以字符长度value.Length为预算但截断点落在单词中间时回退到最近的空白边界丢弃被切到的整个单词。核心逻辑在TruncateFromRight先算出effectiveLength length - truncationString.Length若该位置不是空白即落在词中间用LastIndexOf( , effectiveLength)回退到前一个空格找不到空格说明没有任何完整单词能放下只返回截断标记。左侧截断TruncateFromLeft同理从尾部反向扫描若候选单词超长则只返回标记。测试中的两个边界案例非常直观TruncatorTests.csText longer than truncate length.Truncate(10, Truncator.DynamicLengthAndPreserveWords) Text… // longer 被切到一半整个单词丢弃回退到 Text A Text with delimiter length less than truncate length and the last word fit.Truncate(2, ...) A… // 预算只够放一个单词5. DynamicNumberOfCharactersAndPreserveWordsTruncator字母数字预算 完整单词源码见 DynamicNumberOfCharactersAndPreserveWordTruncator.cs文件名注意为单数 PreserveWord这是 API 文档中唯一被列为 ITruncator 派生类型的实现也是语义最精细的一个length只统计字母数字同时保证单词完整。实现先统计全文字母数字总数totalAlpha未超预算则原样返回截断时按字母数字计数定位候选点若落在词中间则回退/前进到最近的空白边界。其行为在测试中体现得最复杂TruncatorTests.csText with more characters than truncate length.Truncate(10, Truncator.DynamicNumberOfCharactersAndPreserveWords) Text… Text with delimiter length less than truncate length and the last word fit.Truncate(7, ..., ...) Text… Text with additional spaces and null truncate string.Truncate(10, null, ...) Text with // 空格不占字母数字预算因此得以保留选择建议需要严格控制结果字符总长度时用 FixedLength / DynamicLengthAndPreserveWords需要控制可见字符密度、允许空白免费时用两个 NumberOfCharacters 变体按语义单位句子/短语截断时用 FixedNumberOfWords。五种实现彼此独立复杂度与行为都不同适合在不同 UI 约束下替换。扩展方法入口一行代码完成截断虽然 ITruncator 是核心抽象日常使用几乎总是经由 TruncateExtensions.cs 的四个重载进入它们在内部把默认值补齐后转发给 ITruncator// 1. 最简单形式默认 … FixedLength 右侧截断 This is a long string.Truncate(10); // This is a… // 2. 指定截断器默认 … Text with more words than truncate length.Truncate(4, Truncator.FixedNumberOfWords); // Text with more words… // 3. 指定自定义截断标记默认 FixedLength Text longer than truncate length.Truncate(10, ...); // Text lo... Text longer than truncate length.Truncate(10, …, TruncateFrom.Left); // …ng length // 4. 全参数标记 截断器 方向最灵活 This is a long string.Truncate(10, …, Truncator.FixedNumberOfWords, TruncateFrom.Left); // … string四个重载的默认值链条见 TruncateExtensions.cs依次为截断标记默认…Unicode 省略号、截断器默认Truncator.FixedLength、方向默认TruncateFrom.Right。底层最终都汇聚到四参数重载其中truncator参数通过ArgumentNullException.ThrowIfNull做了空引用校验。所有重载对 null 输入都返回 null对不超过预算的字符串都原样返回——这是 Humanizer 截断 API 一贯的幂等友好设计。自定义 ITruncator实现你自己的截断策略内置五种策略无法覆盖需求时实现 ITruncator 只需满足一个方法。一个典型的自定义场景是按标点符号断句 限定句数示例骨架public sealed class SentenceTruncator : ITruncator { [return: NotNullIfNotNull(nameof(value))] public string? Truncate(string? value, int length, string? truncationString, TruncateFrom truncateFrom TruncateFrom.Right) { if (value is null) return null; if (value.Length length || length 0) return value; // 示例从右向左保留最后 length 个以句号结尾的句子 var segments value.Split(., StringSplitOptions.RemoveEmptyEntries); if (segments.Length length) return value; var kept segments[^length..]; return string.Join(., kept) truncationString; } }随后通过扩展方法重载接入统一入口第一句。第二句。第三句。.Truncate(2, ..., new SentenceTruncator(), TruncateFrom.Right);自定义实现需要注意与内置实现保持一致的两条约定null 输入返回 null输出总长含 truncationString尽量不超过length。接口本身不强制这两条但遵循它们才能让自定义截断器在 Humanizer 的调用链中表现可预期。参考实现可对照 ITruncator.cs 与五个内置类的空值/边界处理模式。源码级行为验证边界条件一览从 TruncatorTests.cs 可以沉淀出所有内置实现共同遵守的行为矩阵这也是阅读本文后最值得记住的部分null 输入 → null 输出五种实现与所有扩展方法重载一致空串 → 原样返回空串长度未超预算 → 原样返回不追加任何标记truncationString 为 null 或超长 → 按纯子串截断FixedLength 直接value[..length]FixedNumberOfCharacters 直接切满length个字母数字Dynamic 系列则返回空串或仅返回标记见 TruncatorTests.cs 的Te案例与 #L157 的案例预算不足以容纳任何完整单词 → Dynamic 系列仅返回截断标记如…length计入 truncationString 的字符数五种实现都从预算中扣除标记长度只是 FixedNumberOfCharacters 与 DynamicNumberOfCharactersAndPreserveWords 的预算只统计字母数字。这六条规则配合上面各小节的测试样例构成了 ITruncator 契约从接口签名到具体实现、再到扩展方法入口的完整闭环。在需要为项目挑选截断策略、或排查为什么截断结果多了/少了几个字符时可以按计数口径字符/字母数字/单词→ 是否保留完整单词 → 方向三步快速定位对应实现。赞分享开发工具【免费下载链接】HumanizerHumanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities项目地址https://gitcode.com/gh_mirrors/hu/Humanizer点击查看免费下载相关推荐Humanizer ITruncator 接口深度解析字符串截断的完整指南与五种内置实现Humanizer ITruncator 接口深度解析字符串截断的完整指南与五种内置实现 导读 本文围绕 Humanizer 库的 ITruncator 接口开发工具Humanizer 字符串截断指南TruncateExtensions 与 ITruncator 深度解析Humanizer 字符串截断指南TruncateExtensions 与 ITruncator 深度解析 TruncateExtensions 是 Huma开发工具深入理解 Humanizer 的 ITruncator 接口可插拔的字符串截断引擎深入理解 Humanizer 的 ITruncator 接口可插拔的字符串截断引擎 本篇文章以 Humanizer 的 ITruncator 接口为核心系统开发工具上一篇突破毫秒极限Node.js 微秒时间库 node-microtime 完整使用指南下一篇OpenMDAO完整安装指南快速掌握多学科优化分析工具 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表