news 2026/9/28 3:46:37

Humanizer 格位(GrammaticalCase)枚举完全指南:为俄语、波兰语等屈折语言的日期与时长的格位感知输出

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Humanizer 格位(GrammaticalCase)枚举完全指南:为俄语、波兰语等屈折语言的日期与时长的格位感知输出
  • 开发工具

【免费下载链接】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
点击查看免费下载

导读:本文围绕 Humanizer 公开 API 中的GrammaticalCase枚举展开,说明它如何在日期序数词(ToOrdinalWords)与时长文本(HumanizeWithCase)两类场景中按语法格位(格)选择正确的词形。读完本文,你将掌握该枚举的全部成员语义、Humanizer 对其的校验与异常规则、以及它在俄语、丹麦语、罗马尼亚语、印地语、阿塞拜疆语等文化下的实际输出形态与适用边界。

一、什么是 GrammaticalCase:从 API 文档到源码定义

在 version-3.0.1 的 API 文档 中,GrammaticalCase被定义为:

Options for specifying the desired grammatical case for the output words

即“用于指定输出词汇所需语法格位的选项”。它是 Humanizer 中一个public enum,作用是告诉本地化层:当某门语言的名词、形容词、序数词会随句子成分(主语、宾语、领属者、介词宾语等)发生**词形变化(变格)**时,应该渲染成哪一种形态。对于俄语、波兰语、捷克语、德语、芬兰语等拥有格系统的语言,这一参数直接决定输出词的正确写法;而对于英语这类基本不发生名词变格的语言,该参数通常不产生任何效果。

当前仓库中的实际定义位于 src/Humanizer/GrammaticalCase.cs,其完整枚举成员为28 个(自动按序编号 0~29,Causal为最后一个)。而 v3.0.1 版本 API 文档只收录了前 6 个印欧语系核心格位(编号 0~5),后续版本在此基础上扩展出了更多区域性语言(如芬兰-乌戈尔语系、达罗毗荼语系)所需的格位。

二、全部枚举成员与语义对照表

以下表格整合了 API 文档 中记载的 6 个核心成员与 源码 中扩展的其余成员及其 XML 注释语义:

成员隐含数值语义(对应源码 XML 注释)典型使用语言(推断)
Nominative0表示限定动词的主语(subject of a finite verb)俄语、德语、拉丁语等
Genitive1表示另一名词的领属者(possessor of another noun)俄语、德语、丹麦语
Dative2表示动词的间接宾语(indirect object of a verb)俄语、德语
Accusative3表示动词的直接宾语(direct object of a verb)俄语、德语
Instrumental4表示执行动作时使用的工具(object used in performing an action)俄语、波兰语
Prepositional5表示介词宾语(object of a preposition)俄语
Ablative6表示离开某名词的运动(motion away from a noun)拉丁语、芬兰语
Comitative7表示伴随(accompaniment)芬兰语、爱沙尼亚语
Ergative8表示作格结构中及物动词的施事(agent of a transitive verb in an ergative construction)巴斯克语
Locative9表示位置(location)波兰语、捷克语
Oblique10表示用在格标记后置词或后缀之前的形态(form used before a case-marking postposition or suffix)印地语、旁遮普语
Partitive11表示部分或不定量(partial or indefinite quantity)芬兰语、爱沙尼亚语
Vocative12表示直接称呼(direct address)波兰语、捷克语、乌克兰语
Elative13表示从内部离开的运动(motion out of or away from within)芬兰语、爱沙尼亚语
Illative14表示进入内部的运动(motion into)芬兰语、爱沙尼亚语
Sociative15表示马拉雅拉姆语社会性格的关联或伴随(association or accompaniment)马拉雅拉姆语
Terminative16表示端点或界限(endpoint or limit)爱沙尼亚语
Translative17表示转变进入某种状态(transition into a state)芬兰语、爱沙尼亚语
Absolutive18表示不及物动词的无标记主目或及物动词宾语(unmarked argument of an intransitive verb or object of a transitive verb)巴斯克语
Additive19表示爱沙尼亚语短入格(Estonian short illative form)爱沙尼亚语
Inessive20表示位于内部(location within)芬兰语、爱沙尼亚语
Allative21表示朝上/朝某处的运动(motion onto or toward)芬兰语、爱沙尼亚语
Adessive22表示位于某处/附着(location on or at)芬兰语、爱沙尼亚语
Essive23表示临时状态或角色(temporary state or role)芬兰语、爱沙尼亚语
Abessive24表示缺失或“没有”(absence or being without)芬兰语、爱沙尼亚语
Equative25表示比较或等同(comparison or equivalence)格鲁吉亚语
Directive26表示朝某方向的运动或趋向(motion or direction toward)部分高加索语言
Lative27表示朝目的地的方向(direction toward a destination)芬兰语系部分语言
Benefactive28表示预期受益者(intended beneficiary)部分语言
Causal29表示原因或理由(cause or reason)芬兰语等

说明:数值为源码中按声明顺序的隐含编号,前 6 项与 v3.0.1 API 文档 中标注的显式值(Nominative=0 … Prepositional=5)完全一致。

三、GrammaticalCase 的两大消费入口

Humanizer 中实际接收GrammaticalCase参数的公开 API 主要有两组,均定义在扩展方法中,可通过 Public API 快照 中的ToOrdinalWords(...grammaticalCase)与HumanizeWithCase(...grammaticalCase)签名得到印证。

3.1 日期序数词:ToOrdinalWords(input, GrammaticalCase)

定义于 src/Humanizer/DateToOrdinalWordsExtensions.cs:

  • DateTime.ToOrdinalWords(this DateTime input, GrammaticalCase grammaticalCase);
  • DateOnly.ToOrdinalWords(this DateOnly input, GrammaticalCase grammaticalCase)(仅 .NET 6.0 及以上)。

其实现直接委托给Configurator注册的IDateToOrdinalWordConverter/IDateOnlyToOrdinalWordConverter。从 DefaultDateToOrdinalWordConverter.cs 可以看到默认转换器的行为:

  • 英语文化下输出形如22nd of December, 2020,且Convert(DateTime date, GrammaticalCase grammaticalCase)直接忽略传入的格位参数并调用无格位版本——这正是“英语没有变格,参数无效”的源码证据;
  • 非英语文化则使用当前文化的短日期格式date.ToString("d", culture),并剥离希伯来/阿拉伯日历等输出中可能嵌入的方向性标记(U+200E、U+200F、U+061C),保证嵌入更大序数短语时文本可读。

源码目录src/Humanizer/Localisation/DateToOrdinalWords/下存放了 8 个区域性转换器实现,可以推断俄语、波兰语等带格系统的语言各自实现了格位感知的序数词转换;而 CoverageGapTests.cs 中Assert.Equal("February 22nd, 2024", date.ToOrdinalWords(GrammaticalCase.Genitive))的用例则从测试侧再次确认:英语文化下无论传入哪个格位,输出保持一致。

3.2 时长文本:HumanizeWithCase(TimeSpan, GrammaticalCase, …)

定义于 src/Humanizer/TimeSpanHumanizeExtensions.cs,提供两个重载:

public static string HumanizeWithCase( this TimeSpan timeSpan, GrammaticalCase grammaticalCase, int precision = 1, CultureInfo? culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string? collectionSeparator = ", ") public static string HumanizeWithCase( this TimeSpan timeSpan, GrammaticalCase grammaticalCase, int precision, bool countEmptyUnits, CultureInfo? culture = null, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, string? collectionSeparator = ", ")

参数说明(依据源码 XML 注释):

  • grammaticalCase:用于选择每个时间单位短语的格位;
  • precision:最多返回的时间单位数量(默认 1);
  • countEmptyUnits:空时间单位是否计入precision(前导空单位永不计数);
  • culture:使用的文化,null时取当前线程文化;
  • maxUnit/minUnit:输出的最大/最小时间单位(默认Week/Millisecond);
  • collectionSeparator:组合各时间分段的连接符;传null时使用文化的默认集合格式化器。

它内部先调用ValidateGrammaticalCase做参数校验,再要求当前配置的ITimeSpanHumanizeStrategy必须实现IGrammaticalCaseTimeSpanHumanizeStrategy,否则抛出NotSupportedException。默认策略 DefaultTimeSpanHumanizeStrategy.cs 实现了该接口,并经由IGrammaticalCaseTimeSpanFormatter接口把格位请求转发给 DefaultFormatter.cs 中的TimeSpanHumanize(TimeUnit, int, GrammaticalCase)显式接口实现。

四、源码级校验与异常语义

Humanizer 对GrammaticalCase的校验横跨扩展方法与格式化器两层,理解这些规则有助于规避运行时异常:

4.1 范围校验:仅允许 ≤ Causal 的枚举值

在 TimeSpanHumanizeExtensions.cs 的ValidateGrammaticalCase与 DefaultFormatter.cs 的接口实现中,均采用无符号比较:

if ((uint)grammaticalCase > (uint)GrammaticalCase.Causal) { throw new ArgumentOutOfRangeException( nameof(grammaticalCase), grammaticalCase, "Unsupported grammatical case."); }

即:只要是枚举定义内的值(0~29)就通过校验;若传入未定义的整数值(如(GrammaticalCase)99),则抛出ArgumentOutOfRangeException。

4.2 文化级分类:NotApplicable / Unsupported

DefaultFormatter的格位感知路径依赖源码生成器产出的LocaleDurationCaseTableCatalog(生成输入定义见 src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/LocaleDurationCaseTableCatalogInput.cs),按LocaleDurationCaseClassification分三类处理:

  • Unsupported:该文化具备格位系统,但尚无经核验的时长短语形态——抛出NotSupportedException;
  • NotApplicable:该文化不支持格位时长短语(如英语)——抛出NotSupportedException;
  • 正常分类:通过table.TryGetCase(grammaticalCase, out var caseOverlay)查询,若文化不支持所请求的特定格位,同样抛出NotSupportedException。

此外,格位叠加层还按单位区分SameAsNominative(退回主格形态)、NotApplicable/Unsupported(拒绝)与常规短语渲染三种路径,保证“某个格位对该单位不适用”时给出清晰失败信息而非错误词形。

五、格位感知输出的真实形态:固定用例验证

测试 tests/Humanizer.Tests/Localisation/GeneratedLocaleData/CldrDurationCaseTests.cs 提供了大量“钉死”(pinned)的格位输出样例,可直接作为行为参照:

文化格位单位数量期望输出
da-DKGenitiveDay11 dags
sv-SEGenitiveDay11 dygns
nn-NOGenitiveWeek11 vekes
nb-NOGenitiveWeek11 ukes
ro-ROGenitiveDay1unei zile
am-ETAccusativeDay1አንድ ቀን
hi-INObliqueDay11 दिन
pa-INObliqueWeek11 ਹਫ਼ਤੇ
azDativeDay11 günə

可见:丹麦语、瑞典语、挪威语的领属格会给名词加词尾(如dag → dags、dygn → dygns);罗马尼亚语属格甚至将单位渲染成独立的属格短语unei zile;印地语与旁遮普语则使用Oblique形态(后置词前的变格)。同一测试文件还验证了阿拉伯语(ar)在Nominative/Genitive/Accusative下小时与天的双数、复数形态差异,例如ساعة واحدة(1 小时)、ساعتان(2 小时,主格)、ساعتين(2 小时,属格/宾格)。

测试中还包含“上下文相关失败”用例:索马里语(so)对Nominative抛出包含"does not apply"的NotSupportedException,验证了 4.2 节所述的单位级格位适用性检查。

六、实战示例与注意事项

using Humanizer; using System.Globalization; // 1) 日期序数词:英语下格位参数被忽略 var en = new DateTime(2024, 2, 22) .ToOrdinalWords(GrammaticalCase.Genitive); // "February 22nd, 2024"(与 Nominative 相同) // 2) 时长短语:丹麦语属格 var danish = TimeSpan.FromDays(1).HumanizeWithCase( GrammaticalCase.Genitive, culture: new CultureInfo("da-DK"), maxUnit: Humanizer.TimeUnit.Day, minUnit: Humanizer.TimeUnit.Day); // => "1 dags" // 3) 时长短语:阿塞拜疆语与格 var azeri = TimeSpan.FromDays(1).HumanizeWithCase( GrammaticalCase.Dative, culture: new CultureInfo("az"), maxUnit: Humanizer.TimeUnit.Day, minUnit: Humanizer.TimeUnit.Day); // => "1 günə"

使用要点:

  1. 先确认文化支持:对无格系统的文化(如en-US、zh-CN)调用HumanizeWithCase会因LocaleDurationCaseClassification.NotApplicable抛出NotSupportedException,并非所有语言都适用格位参数;
  2. 异常面较广:除ArgumentOutOfRangeException(非法枚举值)外,还可能在“文化无格位时长表”“文化不支持该格位”“该格位不适用于该单位”三种情况下抛出NotSupportedException,生产代码应做好捕获或先探测支持范围;
  3. 默认参数即可满足多数场景:precision默认 1、maxUnit默认Week、minUnit默认Millisecond,与普通Humanize的默认行为一致,通常只需显式传入grammaticalCase与culture;
  4. DateOnly 重载仅限 .NET 6+:DateOnly版本的ToOrdinalWords(input, grammaticalCase)带有#if NET6_0_OR_GREATER条件编译,面向旧框架时只有DateTime重载可用。

七、总结

GrammaticalCase是 Humanizer 多语言本地化能力在“屈折语言”方向上的关键抽象:它以 28 个成员覆盖印欧、乌拉尔、达罗毗荼、闪含等多个语系的格位系统,通过ToOrdinalWords与HumanizeWithCase两个入口暴露给开发者,底层则由源码生成器按文化产出格位时长表、由DefaultFormatter统一调度。理解其成员语义、文化分类与异常路径,是正确使用 Humanizer 处理俄语、丹麦语、印地语等语言文本输出的前提。

  • 开发工具

【免费下载链接】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
点击查看免费下载
上一篇:AO3 镜像站快速上手指南:5 步拿到稳定访问地址
下一篇:智慧教育平台电子教材下载保姆级教程:5分钟批量搞定电子课本PDF

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 3:45:13

深度解读Work Agent长程任务执行机制:AI自主完成复杂工作的底层逻辑

深度解读Work Agent长程任务执行机制:AI自主完成复杂工作的底层逻辑过去三年AI交互的形态发生了清晰的迭代,最早的生成式AI产品以单轮问答为核心,用户输入一个问题,系统返回对应答案,交互链路在单次对话结束后就完全终…

作者头像 李华
网站建设 2026/9/28 3:45:05

STM32F1 HAL库编译报错根源与精准修复指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 3:41:58

手机本地跑多模态大模型:MNN Chat 从安装到源码的完整拆解

手机本地跑多模态大模型:MNN Chat 从安装到源码的完整拆解 【免费下载链接】MNN MNN: A blazing-fast, lightweight inference engine battle-tested by Alibaba, powering high-performance on-device LLMs and Edge AI. 项目地址: https://gitcode.com/GitHub_T…

作者头像 李华
网站建设 2026/9/28 3:40:47

【C++】 类与对象(二)(2.运算符重载)

目录 赋值运算符重载 1.运算符重载 2.赋值运算符重载 3.日期类实现 取地址运算符重载 1.const 成员 2.取地址运算符重载 运算符重构(operator) 运算符重构是对类这和算符的适配性进行一个适配的重构,就是对于平常的运算符无法进行加减…

作者头像 李华