- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
导读
LetterCasing是 Humanizer 库中定义输出字符串大小写风格的核心枚举,它把标题式、全大写、全小写、句首大写这四种常见的文本转换需求统一抽象为类型安全的枚举值。在 Humanizer 中,它被ApplyCase扩展方法、Humanize(LetterCasing)系列重载以及枚举人性化等场景广泛使用。读完本文,你将掌握每个枚举值的精确行为、底层转换器实现原理、文化感知(culture-aware)细节,以及如何在字符串与枚举人性化流水线中组合使用它们。
枚举定义与四个取值
LetterCasing定义在 src/Humanizer/LetterCasing.cs,是Humanizer命名空间下的一个公共枚举,官方文档对其的定位是"用于指定输出字符串所需字母大小写风格的选项":
namespace Humanizer; /// <summary> /// Options for specifying the desired letter casing for the output string /// </summary> public enum LetterCasing { /// <summary> /// SomeString -> Some String /// </summary> Title, /// <summary> /// SomeString -> SOME STRING /// </summary> AllCaps, /// <summary> /// SomeString -> some string /// </summary> LowerCase, /// <summary> /// SomeString -> Some string /// </summary> Sentence, }四个成员的底层数值分别为0、1、2、3,其语义与示例对照如下(以SomeString为输入):
| 枚举值 | 数值 | 转换效果 | 说明 |
|---|---|---|---|
Title | 0 | SomeString→Some String | 每个单词首字母大写(标题式) |
AllCaps | 1 | SomeString→SOME STRING | 全部转为大写 |
LowerCase | 2 | SomeString→some string | 全部转为小写 |
Sentence | 3 | SomeString→Some string | 仅句首字符大写,其余保持不变 |
从源码结构看,该枚举没有显式指定数值,因此按 C# 枚举默认规则,成员从0开始依次递增,与 website/versioned_docs/version-2.14.1/api/Humanizer.LetterCasing.md 文档中标注的字段值完全一致。
核心入口:CasingExtensions.ApplyCase
LetterCasing枚举本身只表达"意图",真正执行转换的是 src/Humanizer/CasingExtensions.cs 中的ApplyCase扩展方法。它是面向普通字符串的最直接入口:
public static string ApplyCase(this string input, LetterCasing casing) => casing switch { LetterCasing.Title => input.Transform(To.TitleCase), LetterCasing.LowerCase => input.Transform(To.LowerCase), LetterCasing.AllCaps => input.Transform(To.UpperCase), LetterCasing.Sentence => input.Transform(To.SentenceCase), _ => throw new ArgumentOutOfRangeException(nameof(casing)) };该方法在源码注释中给出的行为契约如下:
"some string".ApplyCase(LetterCasing.Title)→"Some String""SOME STRING".ApplyCase(LetterCasing.LowerCase)→"some string""some string".ApplyCase(LetterCasing.AllCaps)→"SOME STRING""some string".ApplyCase(LetterCasing.Sentence)→"Some string"
非法枚举值的处理
注意ApplyCase的 switch 表达式带有_ =>兜底分支,会抛出ArgumentOutOfRangeException。这并非理论上的防御代码——tests/Humanizer.Tests/CoverageGapTests.cs 中就有专门测试验证:
Assert.Throws<ArgumentOutOfRangeException>(() => "hello".ApplyCase((LetterCasing)42));即任何未定义的枚举数值(例如强转的42)都会触发异常,确保不会静默产生未定义的大小写行为。
底层实现:四种 Transformer 的文化感知转换
ApplyCase内部委托给 src/Humanizer/Transformer/To.cs 暴露的四个静态转换器属性:To.TitleCase、To.LowerCase、To.UpperCase、To.SentenceCase。它们都实现了ICulturedStringTransformer接口,因此全部支持传入CultureInfo进行文化感知转换——这是 Humanizer 大小写转换与 .NET 原生 API 相比的重要差异点。
LowerCase / UpperCase:基于 TextInfo 的全量转换
src/Humanizer/Transformer/ToLowerCase.cs 与 src/Humanizer/Transformer/ToUpperCase.cs 的实现非常直白,直接委托给CultureInfo.TextInfo:
public string Transform(string input, CultureInfo culture) => culture.TextInfo.ToLower(input); // ToLowerCase // culture.TextInfo.ToUpper(input); // ToUpperCaseTextInfo.ToLower/ToUpper会依据当前文化(如en-US、tr-TR)的规则进行大小写映射,从而正确处理带口音字符等 Unicode 文本。
Sentence:仅处理首字符,其余原样保留
src/Humanizer/Transformer/ToSentenceCase.cs 的行为值得注意——它只大写第一个字符,绝不触碰其余字符:
public string Transform(string input, CultureInfo culture) { if (input.Length >= 1) { if (char.IsUpper(input[0])) { return input; } return StringHumanizeExtensions.Concat(culture.TextInfo.ToUpper(input[0]), input.AsSpan(1)); } return culture.TextInfo.ToUpper(input); }三个关键细节:
- 首字符已是大写时直接原样返回(短路优化,避免无谓分配);
- 非首字符不做任何小写化,所以
"sOME STRING".ApplyCase(LetterCasing.Sentence)的结果是"SOME STRING"首字符大写后的形态,其余保持原状——这与Title会小写化其余字符的行为有明显区别; - 空字符串走
TextInfo.ToUpper,返回空串,不会崩溃。
Title:最复杂的智能标题转换
src/Humanizer/Transformer/ToTitleCase.cs 是四个转换器中最具 Humanizer 特色的实现,它包含两条转换路径与三个智能规则:
(1)ASCII 快速路径(TryTransformAscii):当输入全部为 ASCII 字符时,走手写的逐字符扫描逻辑,避免正则开销;一旦遇到非 ASCII 字符(current > '\u007F')立即回退到正则路径。
(2)正则路径(TransformWithRegex):使用词模式(\w|[^\u0000-\u007F])+'?\w*匹配单词。在 .NET 7+ 上该正则通过[GeneratedRegex]源生成器编译(见代码中#if NET7_0_OR_GREATER分支),旧框架则使用RegexOptions.Compiled预编译。
(3)三个智能规则:
- 全大写单词保持不变:如果单词本身就是全大写(如
NASA、API),转换器跳过它,不做任何改动,避免把专有名词小写化; - 连字符
'后的字母视为词内部分:扫描逻辑中遇到'会继续向后吞并字母(如don't、o'clock中的后续字母),不会把'当成单词边界; - 短虚词在非句首位置保持小写:
IsArticleOrConjunctionOrPreposition维护了一个固定清单——冠词、连词、介词(a、an、as、at、by、if、in、of、on、or、so、to、up、and、but、for、nor、off、the、via、yet)。当这些词出现在句子中间(wordIndex > 0)时,不会首字母大写,从而得到更符合英文排版习惯的标题,例如"The Lord of the Rings"中的of、the保持小写。
(4)土耳其语 / 阿塞拜疆语特例:UsesCultureSensitiveAsciiCasing会对tr、az开头的文化启用TextInfo的大小写映射。这是为了正确处理土耳其语中无点的ı/ 有点的İ等特殊字母转换,避免 ASCII 快速路径产生错误结果。
与字符串 Humanize 的组合:Humanize(LetterCasing)
LetterCasing最常见的实战场景是作为 src/Humanizer/StringHumanizeExtensions.cs 中Humanize重载的第二个参数——把"拆分单词"与"大小写调整"一步完成:
public static string Humanize(this string input, LetterCasing casing) => input .Humanize() .ApplyCase(casing);从源码注释与测试可见其典型输出:
"PascalCaseInputString".Humanize(LetterCasing.AllCaps)→"PASCAL CASE INPUT STRING""PascalCaseInputString".Humanize(LetterCasing.LowerCase)→"pascal case input string""PascalCaseInputString".Humanize(LetterCasing.Title)→"Pascal Case Input String"
这条重载本质上是Humanize()(把驼峰/下划线拆成空格分隔的单词)与ApplyCase的便捷组合,开发者无需先手动拆分再手动调用ApplyCase。
在枚举人性化中的应用
LetterCasing同样贯穿枚举人性化 API。在 src/Humanizer/EnumHumanizeExtensions.cs 中:
public static string Humanize(this Enum input, LetterCasing casing) => input.Humanize().ApplyCase(casing);文档注释中的示例:
UserType.AnonymousUser.Humanize(LetterCasing.AllCaps)→"ANONYMOUS USER"UserType.AnonymousUser.Humanize(LetterCasing.Title)→"Anonymous User"UserType.AnonymousUser.Humanize(LetterCasing.LowerCase)→"anonymous user"
此外还有带EnumHumanizeSource参数的重载(Humanize(LetterCasing, EnumHumanizeSource)),支持指定从枚举名还是从Display/Description特性取词源。位标志枚举([Flags])场景下同样可用——tests/Humanizer.Tests/BitFieldEnumHumanizeTests.cs 中composite.Humanize(LetterCasing.Title)输出"SpaceX and Name Derived",说明组合枚举成员名也会经过Title风格整理。
在 Inflector 中的内部使用
LetterCasing.Title还被 src/Humanizer/InflectorExtensions.cs 内部使用,用于将去下划线、去短横线后的结果统一应用标题式大小写:
return humanized.Length == 0 ? input : humanized.ApplyCase(LetterCasing.Title);这说明LetterCasing不只是面向外部调用者的公开 API,也是 Humanizer 内部各模块之间传递"大小写意图"的标准媒介。
测试验证与行为保证
Humanizer 为四种大小写风格都建立了针对性的测试矩阵:
- tests/Humanizer.Tests/CasingTests.cs 分别针对
ApplyCaseTitle、ApplyCaseLower、ApplyCaseSentence、ApplyCaseAllCaps四个方向以理论数据([Theory])形式验证输入/输出映射; - tests/Humanizer.Tests/EnumHumanizeTests.cs 将四个枚举值全部纳入
[InlineData(LetterCasing.Title)]等用例,覆盖枚举人性化与大小写组合的每一种取值; - tests/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.Approve_Public_Api.DotNet8_0.verified.txt 等 API 快照文件确认
public static string ApplyCase(this string input, Humanizer.LetterCasing casing)是公开 API 契约的一部分(Net4.8、DotNet8/10/11 各目标框架的快照中均有对应条目),任何签名变更都会触发 API 审批测试失败。
使用建议与注意事项
- 按需选择
Sentence与Title:Sentence只改首字符且不触碰其余文本,适合保留用户原本大小写的场景;Title会小写化单词其余部分并处理虚词,适合生成规范化标题,但对专有名词较多的文本需留意其全大写跳过规则。 - 文化感知是默认行为:四个转换器默认使用
CultureInfo.CurrentCulture(对应Transform(input)无文化重载),需要固定输出时可显式传入CultureInfo调用To.TitleCase.Transform(input, culture)这一层。 - 在 Humanize 流水线中组合使用:处理驼峰标识符时优先使用
"someIdentifier".Humanize(LetterCasing.Title)而非手动拼接,可避免重复编写拆分逻辑;处理枚举展示文本时同理使用Enum.Humanize(LetterCasing.Sentence)等重载。 - 不要传入未定义值:任何超出
0~3范围的枚举值都会触发ArgumentOutOfRangeException,调用方应确保枚举值来自可信来源。
小结
LetterCasing以四个取值覆盖了字符串输出最常用的四种大小写风格,并通过ApplyCase、字符串Humanize、枚举Humanize三条公开链路贯穿 Humanizer 的核心场景。其底层转换器具备文化感知、ASCII 快速路径、全大写跳过、短虚词处理等实现细节,配合完整的测试矩阵与 API 快照,使大小写转换这一看似简单的需求具备了可预测、可验证的工程品质。若需在项目中使用,直接引入 Humanizer 包,即可通过ApplyCase或Humanize(LetterCasing)获得上述全部能力。
- 开发工具
【免费下载链接】Humanizer
Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities
相关推荐
Humanizer 的 LetterCasing 枚举详解:Title、AllCaps、LowerCase 与 Sentence 四种字符串大小写转换
Humanizer 的 LetterCasing 枚举详解:Title、AllCaps、LowerCase 与 Sentence 四种字符串大小写转换 导读 L
开发工具Windows安卓子系统终极指南:WSABuilds完整安装与优化教程
Windows安卓子系统终极指南:WSABuilds完整安装与优化教程 WSABuilds是一个强大的开源项目,为Windows 10和Windows 11用户
开发工具Humanizer 字符串大小写转换详解:ApplyCase 方法与 LetterCasing 枚举全解析
Humanizer 字符串大小写转换详解:ApplyCase 方法与 LetterCasing 枚举全解析 本文围绕 Humanizer 中 CasingExt
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考