EntityFramework 有個慣例,在 DbContext 宣告 DbSet<IEntity> 屬性時會採複數,例如在入門教學中宣告了兩個 Model 類別 - Blog 及 Post,在 BloggingContext 宣告為 DbSet<Blog> Blogs 及 DbSet<Blog> Posts。

在 .NET Framework 時代,有個 System.Data.Entity.Design.PluralizationServices.PluralizationService 提供英文名稱的單數複數轉換(參考:Entity Framework 4 的單複數自動識別功能),寫程式產生器時很好用。

但 EF Core 已無 PluralizationService 可用,Visual Studio 在逆向工程依據現有資料庫建立 DbContext 時是用一套 Humanizer 程式庫,而 EF Core 5 起也納入此程式庫處理 dotnet ef dbcontext scaffold 時的複數名詞轉換。

Humanizer 除了單複數轉換,還有不少好用的功能,像是將某個時間點換算成昨天或三週前、資料量數值轉 KB/MB、句子轉連字線文字(部落格文章標題轉 URL 時很好用)、依指定長度或字數省略過長文字加「…」... 等等。

Humanizer 用法在 Github 有詳細說明,但依慣例還是將較常用到的方法整理成範例,速查兼備忘:

using System.Globalization;
using Humanizer;

Action<string> W = Console.WriteLine;
// UI語系決定顯示結果,先統一切到英文
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

// Pascal 大小寫轉成空白間隔
W("PascalCaseInputStringIsTurnedIntoSentence".Humanize());
//Pascal case input string is turned into sentence

// Camel 大小寫轉成空白間隔
W("camelCaseInputStringIsTurnedIntoSentence".Humanize());
//Camel case input string is turned into sentence

/*
LetterCasing.AllCaps 全大寫
LetterCasing.Title 每個字首字母大寫
LetterCasing.LowerCase 全小寫
LetterCasing.Sentence 句首第一字母大寫
*/

// 連字線轉成空白間隔
W("dash-string-is-turned-into-sentence".Humanize(LetterCasing.Sentence));
//Dash string is turned into sentence

// 省略過長部分接刪節號
W("Long text to truncate".Truncate(10));
//Long text…
// 指定保留 Word 數,亦可指定字元數、省略左邊或右邊
W("Long text to truncate".Truncate(3, Truncator.FixedNumberOfWords));
//Long text to…

// 將時間轉成多久之前、多久之後
W(DateTime.UtcNow.AddHours(-30).Humanize()); //yesterday
W(DateTime.UtcNow.AddHours(-2).Humanize()); //2 hours ago
W(DateTime.UtcNow.AddHours(30).Humanize()); //tomorrow
W(DateTime.UtcNow.AddHours(2).Humanize()); //an hour from now
W(DateTime.UtcNow.AddHours(1).Humanize()); //59 minutes from now
// 時間長度口語化
W(TimeSpan.FromDays(16).Humanize(2)); //2 weeks, 2 days

// 單複數名詞轉換
W("Man".Pluralize()); //Men
W("Indices".Singularize()); //Index
// 若有未包含的單複數字彙可自訂
// Vocabularies.Default.AddIrregular("person", "people");)
// 數量
W("process".ToQuantity(2)); //2 processes
W("process".ToQuantity(3, ShowQuantityAs.Words)); //three processes
// 次序
W(2.ToOrdinalWords()); //second
W(2.Ordinalize()); //2nd
W(5.ToOrdinalWords()); //fifth

// 多字連接
W("some_title for something".Pascalize()); //"SomeTitleForSomething"
W("some_title for something".Camelize()); //"someTitleForSomething"
W("SomeTitle".Underscore()); //"some_title"
W("some_title".Dasherize()); //"some-title"
W("some_title".Hyphenate()); //"some-title"
W("SomeText".Kebaberize()); //"some-text"

// 數字轉口語
W(122.ToWords()); //"one hundred and twenty-two"
W(3501.ToWords()); //"three thousand five hundred and one"

// 羅馬數字
W(8.ToRoman()); //"VIII"

// 距離轉換
W(1230d.ToMetric()); //"1.23k"
W("42.195k".FromMetric().ToString()); //42195

// 資料量
W((1024).Kilobytes().Humanize()); // 1 MB
W((.5).Gigabytes().Humanize());  // 512 MB

// 安裝中文套件 dotnet add package Humanizer.Core.zh-Hant
// 切換 UI Tread 為 zh-TW,部分時間 API 可顯示中文
Thread.CurrentThread.CurrentUICulture = new CultureInfo ("zh-TW");
W(TimeSpan.FromDays(16).Humanize(2)); //2 周, 2 天
W(DateTime.UtcNow.AddHours(-30).Humanize()); //昨天

// 將列舉項目轉成易讀文字
/*
public enum EnumUnderTest
{
    [Description("Custom description")]
    MemberWithDescriptionAttribute,
    MemberWithoutDescriptionAttribute,
    ALLCAPITALS
}
*/
// 依據 DescriptionAttribute
W(EnumUnderTest.MemberWithDescriptionAttribute.Humanize());
//"Custom description"
// 依列舉項目名稱
W(EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize());
//"Member without description attribute"

Introduce to the strings, enums, dates, times, timespans, numbers and quantities displaying library - Humanizer library.


Comments

# by Huang

非常好用,感謝分享

# by 小黑

這個好用ㄟ

Post a comment


98 + 0 =