☰
Humanizer 的 LetterCasing 枚举:四种字符串大小写转换的完整指南
2026/9/27 9:03:14 网站建设 项目流程
  • 开发工具

【免费下载链接】Humanizer

Humanizer meets all your .NET needs for manipulating and displaying strings, enums, dates, times, timespans, numbers and quantities

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载

导读

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为输入):

枚举值数值转换效果说明
Title0SomeString→Some String每个单词首字母大写(标题式)
AllCaps1SomeString→SOME STRING全部转为大写
LowerCase2SomeString→some string全部转为小写
Sentence3SomeString→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); // ToUpperCase

TextInfo.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); }

三个关键细节:

  1. 首字符已是大写时直接原样返回(短路优化,避免无谓分配);
  2. 非首字符不做任何小写化,所以"sOME STRING".ApplyCase(LetterCasing.Sentence)的结果是"SOME STRING"首字符大写后的形态,其余保持原状——这与Title会小写化其余字符的行为有明显区别;
  3. 空字符串走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 审批测试失败。

使用建议与注意事项

  1. 按需选择Sentence与Title:Sentence只改首字符且不触碰其余文本,适合保留用户原本大小写的场景;Title会小写化单词其余部分并处理虚词,适合生成规范化标题,但对专有名词较多的文本需留意其全大写跳过规则。
  2. 文化感知是默认行为:四个转换器默认使用CultureInfo.CurrentCulture(对应Transform(input)无文化重载),需要固定输出时可显式传入CultureInfo调用To.TitleCase.Transform(input, culture)这一层。
  3. 在 Humanize 流水线中组合使用:处理驼峰标识符时优先使用"someIdentifier".Humanize(LetterCasing.Title)而非手动拼接,可避免重复编写拆分逻辑;处理枚举展示文本时同理使用Enum.Humanize(LetterCasing.Sentence)等重载。
  4. 不要传入未定义值:任何超出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

项目地址:https://gitcode.com/gh_mirrors/hu/Humanizer
点击查看免费下载
上一篇:Armbian财务管理策略:IT成本管理策略
下一篇:Obsidian Modular CSS Layout常见问题解答:新手必看

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询