开源项目Humanizer介绍

  Humanizer 能够满足您所有.Net关于操作和展示以下类型的需求,包括字符串、枚举、日期、时间、时间跨度、数字和数量。它采用 MIT 进行授权分发。

 

1、人性化字符串

人性化的字符串扩展名使您可以将原本由计算机处理的字符串转换为更具可读性的人性化字符串。 它的基础是在BDDfy框架中设置的,在该框架中,类名,方法名和属性被转换为易于阅读的句子。

"PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence"

"Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence"

"Underscored_input_String_is_turned_INTO_sentence".Humanize() => "Underscored input String is turned INTO sentence"

请注意,仅包含大写字母且仅包含一个单词的字符串始终被视为首字母缩写词(无论其长度如何)。 为了确保任何字符串都将始终被人性化,您必须使用转换(请参见下面的Transform方法):

// acronyms are left intact
"HTML".Humanize() => "HTML"

// any unbroken upper case string is treated as an acronym
"HUMANIZER".Humanize() => "HUMANIZER"
"HUMANIZER".Transform(To.LowerCase, To.TitleCase) => "Humanizer"

您还可以指定所需的字母大小写:

"CanReturnTitleCase".Humanize(LetterCasing.Title) => "Can Return Title Case"

"Can_return_title_Case".Humanize(LetterCasing.Title) => "Can Return Title Case"

"CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case"

"CanHumanizeIntoUpperCase".Humanize(LetterCasing.AllCaps) => "CAN HUMANIZE INTO UPPER CASE"

LetterCasing API和接受它的方法是V0.2时代的遗留物,将来会不推荐使用。 代替的是,您可以使用下面介绍的Transform方法。

 

2、非人性化的字符串

就像您可以将计算机友好的字符串人性化为人类友好的字符串一样,您也可以将人类友好的字符串人性化为计算机友好的字符串:

"Pascal case input string is turned into sentence".Dehumanize() => "PascalCaseInputStringIsTurnedIntoSentence"

 

3、转换字符串

有一种Transform方法可以代替接受LetterCasing的LetterCasing,ApplyCase和Humanize重载。 转换方法签名如下:

string Transform(this string input, params IStringTransformer[] transformers)

对于字母大小写,还有一些IStringTransformer的现成实现:

"Sentence casing".Transform(To.LowerCase) => "sentence casing"
"Sentence casing".Transform(To.SentenceCase) => "Sentence casing"
"Sentence casing".Transform(To.TitleCase) => "Sentence Casing"
"Sentence casing".Transform(To.UpperCase) => "SENTENCE CASING"

LowerCase是To类的公共静态属性,它返回私有ToLowerCase类的实例,该实例实现IStringTransformer并知道如何将字符串转换为小写。

与ApplyCase和LetterCasing相比,使用Transform和IStringTransformer的好处是LetterCasing是枚举,并且您只能使用框架中的内容,而IStringTransformer是可以在代码库中一次实现并与Transform方法一起使用的接口,从而可以轻松扩展 。

 

4、截断字符串

您可以使用Truncate方法截断字符串:

"Long text to truncate".Truncate(10) => "Long text…"

默认情况下,“ ...”字符用于截断字符串。 使用'...'字符而不是“ ...”的优点是前者仅使用一个字符,因此允许在截断之前显示更多文本。 如果需要,还可以提供自己的截断字符串:

"Long text to truncate".Truncate(10, "---") => "Long te---"

默认的截断策略Truncator.FixedLength是将输入字符串截断为特定长度,包括截断字符串的长度。 还有两种其他的截断器策略:一种用于固定数量的(字母数字)字符,另一种用于固定数量的单词。 要在截断时使用特定的截断器,前面示例中显示的两个Truncate方法都具有重载,允许您指定用于截断的ITruncator实例。 以下是有关如何使用提供的三个截断符的示例:

"Long text to truncate".Truncate(10, Truncator.FixedLength) => "Long text…"
"Long text to truncate".Truncate(10, "---", Truncator.FixedLength) => "Long te---"

"Long text to truncate".Truncate(6, Truncator.FixedNumberOfCharacters) => "Long t…"
"Long text to truncate".Truncate(6, "---", Truncator.FixedNumberOfCharacters) => "Lon---"

"Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords) => "Long text…"
"Long text to truncate".Truncate(2, "---", Truncator.FixedNumberOfWords) => "Long text---"

请注意,您还可以通过实现ITruncator接口来使用创建自己的截断器。

还有一个选项可以选择是从开头(TruncateFrom.Left)还是结尾(TruncateFrom.Right)截断字符串。 如上面的示例所示,默认设置为右侧。 下面的示例显示如何从字符串的开头截断:

"Long text to truncate".Truncate(10, Truncator.FixedLength, TruncateFrom.Left) => "… truncate"
"Long text to truncate".Truncate(10, "---", Truncator.FixedLength, TruncateFrom.Left) => "---runcate"

"Long text to truncate".Truncate(10, Truncator.FixedNumberOfCharacters, TruncateFrom.Left) => "…o truncate"
"Long text to truncate".Truncate(16, "---", Truncator.FixedNumberOfCharacters, TruncateFrom.Left) => "---ext to truncate"

"Long text to truncate".Truncate(2, Truncator.FixedNumberOfWords, TruncateFrom.Left) => "…to truncate"
"Long text to truncate".Truncate(2, "---", Truncator.FixedNumberOfWords, TruncateFrom.Left) => "---to truncate"

 

5、格式化字符串

您可以使用FormatWith()方法设置字符串格式:

"To be formatted -> {0}/{1}.".FormatWith(1, "A") => "To be formatted -> 1/A."

这是基于String.Format的扩展方法,因此确切的规则适用于它。 如果format为null,则将引发ArgumentNullException。 如果传递的参数数目较少,则会引发String.FormatException异常。

您还可以指定区域性以显式用作FormatWith()方法的第一个参数:

"{0:N2}".FormatWith(new CultureInfo("ru-RU"), 6666.66) => "6 666,66"

如果未指定区域性,则使用当前线程的当前区域性。

 

6、人性化枚举

直接在枚举成员上调用ToString通常会给用户带来不理想的输出。 解决方案通常是使用DescriptionAttribute数据注释,然后在运行时读取该注释以获得更友好的输出。 那是一个很好的解决方案。 但是通常,我们只需要在枚举成员的单词之间放置一些空格-这就是String.Humanize()的优点。 对于像这样的枚举:

public enum EnumUnderTest
{
    [Description("Custom description")]
    MemberWithDescriptionAttribute,
    MemberWithoutDescriptionAttribute,
    ALLCAPITALS
}

你会得到:

// DescriptionAttribute is honored
EnumUnderTest.MemberWithDescriptionAttribute.Humanize() => "Custom description"

// In the absence of Description attribute string.Humanizer kicks in
EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize() => "Member without description attribute"

// Of course you can still apply letter casing
EnumUnderTest.MemberWithoutDescriptionAttribute.Humanize().Transform(To.TitleCase) => "Member Without Description Attribute"

您不仅限于DescriptionAttribute作为自定义描述。 应用于具有字符串Description属性的枚举成员的任何属性都将计数。 这是为了帮助缺少DescriptionAttribute的平台,也允许使用DescriptionAttribute的子类。

您甚至可以配置attibute属性的名称以用作描述。

Configurator.EnumDescriptionPropertyLocator = p => p.Name == "Info"

如果需要提供本地化的描述,则可以改用DisplayAttribute数据注释。

public enum EnumUnderTest
{
    [Display(Description = "EnumUnderTest_Member", ResourceType = typeof(Project.Resources))]
    Member
}

你会得到:

EnumUnderTest.Member.Humanize() => "content" // from Project.Resources found under "EnumUnderTest_Member" resource key

希望这将有助于避免乱定义带有不必要属性的枚举!

 

7、使枚举非人性化

将字符串人性化,使其原本是人性化的枚举! 该API如下所示:

public static TTargetEnum DehumanizeTo<TTargetEnum>(this string input)

用法是:

"Member without description attribute".DehumanizeTo<EnumUnderTest>() => EnumUnderTest.MemberWithoutDescriptionAttribute

就像Humanize API一样,它使用Description属性。 您无需提供在人性化过程中提供的外壳:它可以弄清楚。

当在编译时不知道原始Enum时,还有一个非泛型对应项:

public static Enum DehumanizeTo(this string input, Type targetEnum, NoMatch onNoMatch = NoMatch.ThrowsException)

可以像这样使用:

"Member without description attribute".DehumanizeTo(typeof(EnumUnderTest)) => EnumUnderTest.MemberWithoutDescriptionAttribute

默认情况下,两个方法都无法将提供的输入与目标枚举进行匹配时抛出NoMatchFoundException。 在非泛型方法中,您还可以通过将第二个可选参数设置为NoMatch.ReturnsNull来要求该方法返回null。

 

8、人性化DateTime

您可以对DateTime或DateTimeOffset的实例进行人性化,并返回一个字符串,该字符串告诉您时间上的倒退或前进时间:

DateTime.UtcNow.AddHours(-30).Humanize() => "yesterday"
DateTime.UtcNow.AddHours(-2).Humanize() => "2 hours ago"

DateTime.UtcNow.AddHours(30).Humanize() => "tomorrow"
DateTime.UtcNow.AddHours(2).Humanize() => "2 hours from now"

DateTimeOffset.UtcNow.AddHours(1).Humanize() => "an hour from now"

Humanizer支持本地和UTC日期以及具有偏移量的日期(DateTimeOffset)。 您还可以提供要与输入日期进行比较的日期。 如果为null,它将使用当前日期作为比较基础。 另外,可以明确指定要使用的文化。 如果不是,则使用当前线程的当前UI文化。 这是API签名:

public static string Humanize(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null)
public static string Humanize(this DateTimeOffset input, DateTimeOffset? dateToCompareAgainst = null, CultureInfo culture = null)

此方法有许多本地化版本。 以下是一些示例:

// In ar culture
DateTime.UtcNow.AddDays(-1).Humanize() => "أمس"
DateTime.UtcNow.AddDays(-2).Humanize() => "منذ يومين"
DateTime.UtcNow.AddDays(-3).Humanize() => "منذ 3 أيام"
DateTime.UtcNow.AddDays(-11).Humanize() => "منذ 11 يوم"

// In ru-RU culture
DateTime.UtcNow.AddMinutes(-1).Humanize() => "минуту назад"
DateTime.UtcNow.AddMinutes(-2).Humanize() => "2 минуты назад"
DateTime.UtcNow.AddMinutes(-10).Humanize() => "10 минут назад"
DateTime.UtcNow.AddMinutes(-21).Humanize() => "21 минуту назад"
DateTime.UtcNow.AddMinutes(-22).Humanize() => "22 минуты назад"
DateTime.UtcNow.AddMinutes(-40).Humanize() => "40 минут назад"

DateTime.Humanize有两种策略:如上所述的默认策略和基于精度的策略。 要使用基于精度的策略,您需要对其进行配置:

Configurator.DateTimeHumanizeStrategy = new PrecisionDateTimeHumanizeStrategy(precision: .75);
Configurator.DateTimeOffsetHumanizeStrategy = new PrecisionDateTimeOffsetHumanizeStrategy(precision: .75); // configure when humanizing DateTimeOffset

默认精度设置为.75,但是您也可以传递所需的精度。 将精度设置为0.75:

44 seconds => 44 seconds ago/from now
45 seconds => one minute ago/from now
104 seconds => one minute ago/from now
105 seconds => two minutes ago/from now

25 days => a month ago/from now

日期没有非人性化,因为人性化是有损的转换,并且人类友好的日期是不可逆的。

 

9、人性化的时间跨度

您可以在TimeSpan上调用Humanize以获得人性化的表示形式:

TimeSpan.FromMilliseconds(1).Humanize() => "1 millisecond"
TimeSpan.FromMilliseconds(2).Humanize() => "2 milliseconds"
TimeSpan.FromDays(1).Humanize() => "1 day"
TimeSpan.FromDays(16).Humanize() => "2 weeks"

TimeSpan.Humanize有一个可选的precision参数,它允许您指定返回值的精度。 精度的默认值为1,这意味着仅返回最大的时间单位,如您在TimeSpan.FromDays(16).Humanize()中看到的那样。 以下是一些指定精度的示例:

TimeSpan.FromDays(1).Humanize(precision:2) => "1 day" // no difference when there is only one unit in the provided TimeSpan
TimeSpan.FromDays(16).Humanize(2) => "2 weeks, 2 days"

// the same TimeSpan value with different precision returns different results
TimeSpan.FromMilliseconds(1299630020).Humanize() => "2 weeks"
TimeSpan.FromMilliseconds(1299630020).Humanize(3) => "2 weeks, 1 day, 1 hour"
TimeSpan.FromMilliseconds(1299630020).Humanize(4) => "2 weeks, 1 day, 1 hour, 30 seconds"
TimeSpan.FromMilliseconds(1299630020).Humanize(5) => "2 weeks, 1 day, 1 hour, 30 seconds, 20 milliseconds"

默认情况下,使用精度参数时,空时间单位不计入返回值的精度。 如果您不需要这种行为,则可以将重载的TimeSpan.Humanize方法与countEmptyUnits参数一起使用。 前导的空时间单位永远不会计数。 这是显示空单位计数的区别的示例:

TimeSpan.FromMilliseconds(3603001).Humanize(3) => "1 hour, 3 seconds, 1 millisecond"
TimeSpan.FromMilliseconds(3603001).Humanize(3, countEmptyUnits:true) => "1 hour, 3 seconds"

此方法有许多本地化版本:

// in de-DE culture
TimeSpan.FromDays(1).Humanize() => "Ein Tag"
TimeSpan.FromDays(2).Humanize() => "2 Tage"

// in sk-SK culture
TimeSpan.FromMilliseconds(1).Humanize() => "1 milisekunda"
TimeSpan.FromMilliseconds(2).Humanize() => "2 milisekundy"
TimeSpan.FromMilliseconds(5).Humanize() => "5 milisekúnd"

可以明确指定要使用的文化。 如果不是,则使用当前线程的当前UI文化。 例:

TimeSpan.FromDays(1).Humanize(culture: "ru-RU") => "один день"

另外,可以指定最短的时间单位,以避免滚动到较小的单位。 例如:

TimeSpan.FromMilliseconds(122500).Humanize(minUnit: TimeUnit.Second) => "2 minutes, 2 seconds"    // instead of 2 minutes, 2 seconds, 500 milliseconds
TimeSpan.FromHours(25).Humanize(minUnit: TimeUnit.Day) => "1 Day"   //instead of 1 Day, 1 Hour

另外,可以指定最大时间单位以避免累加到下一个最大单位。 例如:

TimeSpan.FromDays(7).Humanize(maxUnit: TimeUnit.Day) => "7 days"    // instead of 1 week
TimeSpan.FromMilliseconds(2000).Humanize(maxUnit: TimeUnit.Millisecond) => "2000 milliseconds"    // instead of 2 seconds

默认的maxUnit为TimeUnit.Week,因为它可以提供准确的结果。 您可以将此值增加到TimeUnit.Month或TimeUnit.Year,这将为您提供基于每年365.2425天和每月30.436875天的近似值。 因此,月份的间隔为30到31天,每四年为366天。

TimeSpan.FromDays(486).Humanize(maxUnit: TimeUnit.Year, precision: 7) => "1 year, 3 months, 29 days" // One day further is 1 year, 4 month
TimeSpan.FromDays(517).Humanize(maxUnit: TimeUnit.Year, precision: 7) => "1 year, 4 months, 30 days" // This month has 30 days and one day further is 1 year, 5 months

如果有多个时间单位,则使用“,”字符串将它们组合起来:

TimeSpan.FromMilliseconds(1299630020).Humanize(3) => "2 weeks, 1 day, 1 hour"

当TimeSpan为零时,默认行为将返回“ 0”加上最小时间单位。 但是,如果在调用Humanize时将true分配给toWords,则该方法将返回“ no time”。 例如:

TimeSpan.Zero.Humanize(1) => "0 milliseconds"
TimeSpan.Zero.Humanize(1, toWords: true) => "no time"
TimeSpan.Zero.Humanize(1, minUnit: Humanizer.Localisation.TimeUnit.Second) => "0 seconds"

使用collectionSeparator参数,可以指定自己的分隔符字符串:

TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: " - ") => "2 weeks - 1 day - 1 hour"

也可以使用当前区域性的集合格式化程序来组合时间单位。 为此,将null指定为collectionSeparator参数:

// in en-US culture
TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 weeks, 1 day, and 1 hour"

// in de-DE culture
TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) => "2 Wochen, Ein Tag und Eine Stunde"

如果单词优先于数字,则可以设置toWords:true参数,以将人性化的TimeSpan中的数字转换为单词:

TimeSpan.FromMilliseconds(1299630020).Humanize(3,toWords:true)=>“两个星期,一天,一个小时”

 

10、人性化集合

您可以在任何IEnumerable上调用Humanize,以获取格式正确的字符串,该字符串表示集合中的对象。 默认情况下,将在每个项目上调用ToString()以获取其表示形式,但是可以将格式化函数传递给Humanize。 此外,提供了一个默认的分隔符(英语中为“ and”),但是可以将其他分隔符传递给Humanize。

例如:

class SomeClass
{
    public string SomeString;
    public int SomeInt;
    public override string ToString()
    {
        return "Specific String";
    }
}

string FormatSomeClass(SomeClass sc)
{
    return string.Format("SomeObject #{0} - {1}", sc.SomeInt, sc.SomeString);
}

var collection = new List<SomeClass>
{
    new SomeClass { SomeInt = 1, SomeString = "One" },
    new SomeClass { SomeInt = 2, SomeString = "Two" },
    new SomeClass { SomeInt = 3, SomeString = "Three" }
};

collection.Humanize()                                    // "Specific String, Specific String, and Specific String"
collection.Humanize("or")                                // "Specific String, Specific String, or Specific String"
collection.Humanize(FormatSomeClass)                     // "SomeObject #1 - One, SomeObject #2 - Two, and SomeObject #3 - Three"
collection.Humanize(sc => sc.SomeInt.Ordinalize(), "or") // "1st, 2nd, or 3rd"

修剪项目,并跳过空白(NullOrWhitespace)项目。 这导致干净的逗号标点。 (如果有自定义格式器功能,则此功能仅适用于格式器的输出。)

您可以通过实现ICollectionFormatter并向Configurator.CollectionFormatters注册它来提供自己的集合格式化程序。

 

11、Inflector 方法

还有一些 inflector 方法:

 

复数

在考虑不规则和不可数词的情况下,将提供的输入复数化:

"Man".Pluralize() => "Men"
"string".Pluralize() => "strings"

通常,您将对单个单词调用Pluralize,但如果不确定单词的奇异性,则可以使用可选的inputIsKnownToBeSingular参数调用该方法:

"Men".Pluralize(inputIsKnownToBeSingular: false) => "Men"
"Man".Pluralize(inputIsKnownToBeSingular: false) => "Men"
"string".Pluralize(inputIsKnownToBeSingular: false) => "strings"

具有复数参数的Pluralize重载已过时,在2.0版中已删除。

 

单数化

单数将提供的输入单数化,同时考虑不规则和不可数的单词:

"Men".Singularize() => "Man"
"strings".Singularize() => "string"

通常,您会在一个复数单词上调用单数化,但是如果不确定该单词的复数形式,则可以使用可选的inputIsKnownToBePlural参数调用该方法:

"Men".Singularize(inputIsKnownToBePlural: false) => "Man"
"Man".Singularize(inputIsKnownToBePlural: false) => "Man"
"strings".Singularize(inputIsKnownToBePlural: false) => "string"

具有复数参数的Singularize重载已过时,并且在2.0版中已删除。

 

12、添加单词

有时,您可能需要从单数/复数词汇表中添加一条规则(以下示例已在Inflector使用的默认词汇表中):

// Adds a word to the vocabulary which cannot easily be pluralized/singularized by RegEx.
// Will match both "salesperson" and "person".
Vocabularies.Default.AddIrregular("person", "people");

// To only match "person" and not "salesperson" you would pass false for the 'matchEnding' parameter.
Vocabularies.Default.AddIrregular("person", "people", matchEnding: false);

// Adds an uncountable word to the vocabulary.  Will be ignored when plurality is changed:
Vocabularies.Default.AddUncountable("fish");

// Adds a rule to the vocabulary that does not follow trivial rules for pluralization:
Vocabularies.Default.AddPlural("bus", "buses");

// Adds a rule to the vocabulary that does not follow trivial rules for singularization
// (will match both "vertices" -> "vertex" and "indices" -> "index"):
Vocabularies.Default.AddSingular("(vert|ind)ices$", "$1ex");

到数量

很多时候,您想调用单数化和复数化为单词加上数字。 例如 “ 2个请求”,“ 3个男人”。 ToQuantity为提供的单词加上数字前缀,并相应地对该单词进行复数或单数化:

"case".ToQuantity(0) => "0 cases"
"case".ToQuantity(1) => "1 case"
"case".ToQuantity(5) => "5 cases"
"man".ToQuantity(0) => "0 men"
"man".ToQuantity(1) => "1 man"
"man".ToQuantity(2) => "2 men"

ToQuantity可以判断输入单词是单数还是复数,并在必要时将单数或复数:

"men".ToQuantity(2) => "2 men"
"process".ToQuantity(2) => "2 processes"
"process".ToQuantity(1) => "1 process"
"processes".ToQuantity(2) => "2 processes"
"processes".ToQuantity(1) => "1 process"

您还可以将第二个参数ShowQuantityAs传递给ToQuantity,以指定希望如何输出提供的数量。 默认值为ShowQuantityAs.Numeric,这是我们在上面看到的。 其他两个值是ShowQuantityAs.Words和ShowQuantityAs.None。

"case".ToQuantity(5, ShowQuantityAs.Words) => "five cases"
"case".ToQuantity(5, ShowQuantityAs.None) => "cases"

还有一个重载,允许您格式化数字。 您可以传递要使用的格式和文化。

"dollar".ToQuantity(2, "C0", new CultureInfo("en-US")) => "$2 dollars"
"dollar".ToQuantity(2, "C2", new CultureInfo("en-US")) => "$2.00 dollars"
"cases".ToQuantity(12000, "N0") => "12,000 cases"

序数化

序数化将数字转换为序数字符串,用于表示有序序列(例如1st,2nd,3rd,4th)中的位置:

1.Ordinalize() => "1st"
5.Ordinalize() => "5th"

您还可以在数字字符串上调用Ordinalize并获得相同的结果:“ 21” .Ordinalize()=>“ 21st”

序数化还支持两种形式的语法性别。 您可以将一个参数传递给Ordinalize,以指定数字应以哪种性别输出。可能的值为GrammaticalGender.Masculine,GrammmicalGender.Feminine和GrammaticalGender.Neuter:

// for Brazilian Portuguese locale
1.Ordinalize(GrammaticalGender.Masculine) => ""
1.Ordinalize(GrammaticalGender.Feminine) => ""
1.Ordinalize(GrammaticalGender.Neuter) => ""
"2".Ordinalize(GrammaticalGender.Masculine) => ""
"2".Ordinalize(GrammaticalGender.Feminine) => ""
"2".Ordinalize(GrammaticalGender.Neuter) => ""

显然,这仅适用于某些文化。 对于其他通过性别或根本不通过的人,结果没有任何区别。

标题化

Titleize将输入的单词转换为Title大小写; 等效于“某些标题”。Humanize(LetterCasing.Title)

Pascalize

Pascalize将输入的单词转换为UpperCamelCase,还删除下划线和空格:

"some_title for something".Pascalize() => "SomeTitleForSomething"

Camelize

Camelize的行为与Pascalize相同,但第一个字符为小写:

"some_title for something".Camelize() => "someTitleForSomething"

下划线

Underscore用下划线分隔输入的单词:

"SomeTitle".Underscore() => "some_title"

Dasherize & Hyphenate

Dasherize和Hyphenate用下划线替换下划线:

"some_title".Dasherize() => "some-title"
"some_title".Hyphenate() => "some-title"
Kebaberize
Kebaberize用连字符分隔输入的单词,所有单词都转换为小写
"SomeText".Kebaberize() => "some-text"

 

13、流利的日期

Humanizer提供了一种流利的API来处理DateTime和TimeSpan,如下所示:

TimeSpan方法:

2.Milliseconds() => TimeSpan.FromMilliseconds(2)
2.Seconds() => TimeSpan.FromSeconds(2)
2.Minutes() => TimeSpan.FromMinutes(2)
2.Hours() => TimeSpan.FromHours(2)
2.Days() => TimeSpan.FromDays(2)
2.Weeks() => TimeSpan.FromDays(14)

每月或一年都没有流利的API,因为一个月可能有28到31天,一年可能是365或366天。

您可以使用这些方法来替换

DateTime.Now.AddDays(2).AddHours(3).AddMinutes(-5)

DateTime.Now + 2.Days() + 3.Hours() - 5.Minutes()

还可以使用三类流利的方法来处理DateTime:

In.TheYear(2010) // Returns the first of January of 2010
In.January // Returns 1st of January of the current year
In.FebruaryOf(2009) // Returns 1st of February of 2009

In.One.Second //  DateTime.UtcNow.AddSeconds(1);
In.Two.SecondsFrom(DateTime dateTime)
In.Three.Minutes // With corresponding From method
In.Three.Hours // With corresponding From method
In.Three.Days // With corresponding From method
In.Three.Weeks // With corresponding From method
In.Three.Months // With corresponding From method
In.Three.Years // With corresponding From method

On.January.The4th // Returns 4th of January of the current year
On.February.The(12) // Returns 12th of Feb of the current year

和一些扩展方法:

var someDateTime = new DateTime(2011, 2, 10, 5, 25, 45, 125);

// Returns new DateTime(2008, 2, 10, 5, 25, 45, 125) changing the year to 2008
someDateTime.In(2008)

// Returns new DateTime(2011, 2, 10, 2, 25, 45, 125) changing the hour to 2:25:45.125
someDateTime.At(2)

// Returns new DateTime(2011, 2, 10, 2, 20, 15, 125) changing the time to 2:20:15.125
someDateTime.At(2, 20, 15)

// Returns new DateTime(2011, 2, 10, 12, 0, 0) changing the time to 12:00:00.000
someDateTime.AtNoon()

// Returns new DateTime(2011, 2, 10, 0, 0, 0) changing the time to 00:00:00.000
someDateTime.AtMidnight()

显然,您也可以将这些方法链接在一起。 例如 2010年11月13日在中午+ 5分钟()

 

14、数字到数字

Humanizer提供了一种流畅的API,该API以更清晰的方式生成(通常是很大的)数字:

1.25.Billions() => 1250000000
3.Hundreds().Thousands() => 300000

 

15、数字到单词

Humanizer可以使用ToWords扩展名将数字更改为单词:

1.ToWords() => "one"
10.ToWords() => "ten"
11.ToWords() => "eleven"
122.ToWords() => "one hundred and twenty-two"
3501.ToWords() => "three thousand five hundred and one"

您还可以将第二个参数GrammaticalGender传递给ToWords,以指定应该输出数字的性别。可能的值为GrammaticalGender.Masculine,GrammaticalGender.Feminine和GrammaticalGender.Neuter:

// for Russian locale
1.ToWords(GrammaticalGender.Masculine) => "один"
1.ToWords(GrammaticalGender.Feminine) => "одна"
1.ToWords(GrammaticalGender.Neuter) => "одно"
// for Arabic locale
1.ToWords(GrammaticalGender.Masculine) => "واحد"
1.ToWords(GrammaticalGender.Feminine) => "واحدة"
1.ToWords(GrammaticalGender.Neuter) => "واحد"
(-1).ToWords() => "ناقص واحد"

显然,这仅适用于某些文化。 对于传递性别的其他人来说,结果没有任何区别。

另外,可以明确指定要使用的文化。 如果不是,则使用当前线程的当前UI文化。 这是一个例子:

11.ToWords(new CultureInfo("en")) => "eleven"
1.ToWords(GrammaticalGender.Masculine, new CultureInfo("ru")) => "один"

 

16、数字到序数词

这是将ToWords与Ordinalize混合在一起的一种。 您可以在数字上调用ToOrdinalWords以获得数字中单词的序号表示! 例如:

0.ToOrdinalWords() => "zeroth"
1.ToOrdinalWords() => "first"
2.ToOrdinalWords() => "second"
8.ToOrdinalWords() => "eighth"
10.ToOrdinalWords() => "tenth"
11.ToOrdinalWords() => "eleventh"
12.ToOrdinalWords() => "twelfth"
20.ToOrdinalWords() => "twentieth"
21.ToOrdinalWords() => "twenty first"
121.ToOrdinalWords() => "hundred and twenty first"

ToOrdinalWords也支持语法性别。 您可以将第二个参数传递给ToOrdinalWords以指定输出的性别。 可能的值为GrammaticalGender.Masculine,GrammmicalGender.Feminine和GrammaticalGender.Neuter:

// for Brazilian Portuguese locale
1.ToOrdinalWords(GrammaticalGender.Masculine) => "primeiro"
1.ToOrdinalWords(GrammaticalGender.Feminine) => "primeira"
1.ToOrdinalWords(GrammaticalGender.Neuter) => "primeiro"
2.ToOrdinalWords(GrammaticalGender.Masculine) => "segundo"
2.ToOrdinalWords(GrammaticalGender.Feminine) => "segunda"
2.ToOrdinalWords(GrammaticalGender.Neuter) => "segundo"
// for Arabic locale
1.ToOrdinalWords(GrammaticalGender.Masculine) => "الأول"
1.ToOrdinalWords(GrammaticalGender.Feminine) => "الأولى"
1.ToOrdinalWords(GrammaticalGender.Neuter) => "الأول"
2.ToOrdinalWords(GrammaticalGender.Masculine) => "الثاني"
2.ToOrdinalWords(GrammaticalGender.Feminine) => "الثانية"
2.ToOrdinalWords(GrammaticalGender.Neuter) => "الثاني"

显然,这仅适用于某些文化。 对于传递性别的其他人来说,结果没有任何区别。

另外,可以明确指定要使用的文化。 如果不是,则使用当前线程的当前UI文化。 这是一个例子:

10.ToOrdinalWords(new CultureInfo("en-US")) => "tenth"
1.ToOrdinalWords(GrammaticalGender.Masculine, new CulureInfo("pt-BR")) => "primeiro"

 

17、日期时间到序数词

这是Ordinalize的扩展

// for English UK locale
new DateTime(2015, 1, 1).ToOrdinalWords() => "1st January 2015"
new DateTime(2015, 2, 12).ToOrdinalWords() => "12th February 2015"
new DateTime(2015, 3, 22).ToOrdinalWords() => "22nd March 2015"
// for English US locale
new DateTime(2015, 1, 1).ToOrdinalWords() => "January 1st, 2015"
new DateTime(2015, 2, 12).ToOrdinalWords() => "February 12th, 2015"
new DateTime(2015, 3, 22).ToOrdinalWords() => "March 22nd, 2015"

ToOrdinalWords也支持语法大小写。 您可以将第二个参数传递给ToOrdinalWords以指定输出的大小写。 可能的值是GrammaticalCase.Nominative,GrammmicalCase.Genitive,GrammmicalCase.Dative,GrammmicalCase.Accusative,GrammmicalCase.Instrumental和GraammaticalGender。介词:

显然,这仅适用于某些文化。 对于其他人来说,通过案例不会对结果产生任何影响。

 

18、罗马数字

Humanizer可以使用ToRoman扩展名将数字更改为罗马数字。 数字1到10可以用罗马数字表示如下:

1.ToRoman() => "I"
2.ToRoman() => "II"
3.ToRoman() => "III"
4.ToRoman() => "IV"
5.ToRoman() => "V"
6.ToRoman() => "VI"
7.ToRoman() => "VII"
8.ToRoman() => "VIII"
9.ToRoman() => "IX"
10.ToRoman() => "X"

也可以使用FromRoman扩展名进行反向操作。

"I".FromRoman() => 1
"II".FromRoman() => 2
"III".FromRoman() => 3
"IV".FromRoman() => 4
"V".FromRoman() => 5

请注意,只有小于4000的整数才能转换为罗马数字。

 

19、公制数字
Humanizer可以使用ToMetric扩展名将数字更改为公制数字。 数字1、1230和0.1可以用公制数字表示,如下所示:
1d.ToMetric() => "1"
1230d.ToMetric() => "1.23k"
0.1d.ToMetric() => "100m"

也可以使用FromMetric扩展进行相反的操作。

1d.ToMetric() => "1"
1230d.ToMetric() => "1.23k"
0.1d.ToMetric() => "100m"

"1".FromMetric() => 1
"1.23k".FromMetric() => 1230
"100m".FromMetric() => 0.1

 

20、字节大小

Humanizer包含出色的ByteSize库的端口。 对ByteSize进行了许多更改和添加,以使与ByteSize的交互更容易且与Humanizer API更加一致。 这是一些如何从数字转换为字节大小以及在大小幅值之间转换的示例:

var fileSize = (10).Kilobytes();

fileSize.Bits      => 81920
fileSize.Bytes     => 10240
fileSize.Kilobytes => 10
fileSize.Megabytes => 0.009765625
fileSize.Gigabytes => 9.53674316e-6
fileSize.Terabytes => 9.31322575e-9

有几种扩展方法可让您将数字转换为ByteSize实例:

3.Bits();
5.Bytes();
(10.5).Kilobytes();
(2.5).Megabytes();
(10.2).Gigabytes();
(4.7).Terabytes();

您还可以使用+/-运算符和加/减方法对值进行加/减:

var total = (10).Gigabytes() + (512).Megabytes() - (2.5).Gigabytes();
total.Subtract((2500).Kilobytes()).Add((25).Megabytes());

ByteSize对象包含两个属性,它们代表最大的度量标准前缀符号和值:

var maxFileSize = (10).Kilobytes();

maxFileSize.LargestWholeNumberSymbol;  // "KB"
maxFileSize.LargestWholeNumberValue;   // 10

如果要使用字符串表示形式,则可以在ByteSize实例上互换调用ToString或Humanize:

7.Bits().ToString();           // 7 b
8.Bits().ToString();           // 1 B
(.5).Kilobytes().Humanize();   // 512 B
(1000).Kilobytes().ToString(); // 1000 KB
(1024).Kilobytes().Humanize(); // 1 MB
(.5).Gigabytes().Humanize();   // 512 MB
(1024).Gigabytes().ToString(); // 1 TB

您还可以选择提供期望的字符串表示形式的格式。 格式化程序可以包含要显示的值的符号:b,B,KB,MB,GB,TB。 格式化程序使用内置的double.ToString方法,将#。##作为默认格式,该格式将数字四舍五入到小数点后两位:

var b = (10.505).Kilobytes();

// Default number format is #.##
b.ToString("KB");         // 10.52 KB
b.Humanize("MB");         // .01 MB
b.Humanize("b");          // 86057 b

// Default symbol is the largest metric prefix value >= 1
b.ToString("#.#");        // 10.5 KB

// All valid values of double.ToString(string format) are acceptable
b.ToString("0.0000");     // 10.5050 KB
b.Humanize("000.00");     // 010.51 KB

// You can include number format and symbols
b.ToString("#.#### MB");  // .0103 MB
b.Humanize("0.00 GB");    // 0 GB
b.Humanize("#.## B");     // 10757.12 B

如果要使用完整单词的字符串表示形式,可以在ByteSize实例上调用ToFullWords:

7.Bits().ToFullWords();           // 7 bits
8.Bits().ToFullWords();           // 1 byte
(.5).Kilobytes().ToFullWords();   // 512 bytes
(1000).Kilobytes().ToFullWords(); // 1000 kilobytes
(1024).Kilobytes().ToFullWords(); // 1 megabyte
(.5).Gigabytes().ToFullWords();   // 512 megabytes
(1024).Gigabytes().ToFullWords(); // 1 terabyte

没有Dehumanize方法可以将字符串表示形式转换回ByteSize实例。 但是您可以对ByteSize使用Parse和TryParse来做到这一点。 像其他TryParse方法一样,ByteSize.TryParse返回布尔值,该值指示解析是否成功。 如果解析了该值,则将其输出到提供的out参数:

 

ByteSize output;
ByteSize.TryParse("1.5mb", out output);

// Invalid
ByteSize.Parse("1.5 b");   // Can't have partial bits

// Valid
ByteSize.Parse("5b");
ByteSize.Parse("1.55B");
ByteSize.Parse("1.55KB");
ByteSize.Parse("1.55 kB "); // Spaces are trimmed
ByteSize.Parse("1.55 kb");
ByteSize.Parse("1.55 MB");
ByteSize.Parse("1.55 mB");
ByteSize.Parse("1.55 mb");
ByteSize.Parse("1.55 GB");
ByteSize.Parse("1.55 gB");
ByteSize.Parse("1.55 gb");
ByteSize.Parse("1.55 TB");
ByteSize.Parse("1.55 tB");
ByteSize.Parse("1.55 tb");

最后,如果您需要计算传输一定数量字节的速率,则可以使用ByteSize的Per方法。 Per方法接受一个参数-字节的测量间隔; 这是传输字节所花费的时间。

Per方法返回具有Humanize方法的ByteRate类。 默认情况下,速率以秒为单位(例如MB / s)。 但是,如果需要,可以在另一个间隔内将TimeUnit传递给Humanize。 有效间隔是TimeUnit.Second,TimeUnit.Minute和TimeUnit.Hour。 下面是每个间隔的示例以及字节率的示例。

var size = ByteSize.FromMegabytes(10);
var measurementInterval = TimeSpan.FromSeconds(1);

var text = size.Per(measurementInterval).Humanize();
// 10 MB/s

text = size.Per(measurementInterval).Humanize(TimeUnit.Minute);
// 600 MB/min

text = size.Per(measurementInterval).Humanize(TimeUnit.Hour);
// 35.15625 GB/hour

您可以为人性化输出的字节部分指定格式:

 
19854651984.Bytes().Per(1.Seconds()).Humanize("#.##");
// 18.49 GB/s

 

21、角度到单词

Humanizer包括将数字标题更改为单词的方法。 标题可以是双精度,而结果将是字符串。 您可以选择返回标题的完整表示形式(例如,北,东,南或西),简短表示形式(例如,N,E,S,W)还是Unicode箭头字符(例如,↑,→,↓,←) )。

360.ToHeading();
// north
720.ToHeading();
// north

为了检索标题的简短版本,您可以使用以下调用:

180.ToHeading(true);
// S
360.ToHeading(true);
// N

请注意,文字表示的最大偏差为11.25°。

最重要的是,这些方法都有一个重载,您可以使用它提供一个CultureInfo对象,以确定要返回的本地化结果。

要检索表示标题的箭头,请使用以下方法:

90.ToHeadingArrow();
//
225.ToHeadingArrow();
//

标题的箭头表示最大偏差为22.5°。

为了检索基于短文本表示形式的标题(例如N,E,S,W),可以使用以下方法:

"S".FromShortHeading();
// 180
"SW".FromShortHeading();
// 225

 

22、元组化

Humanizer 可以使用Tupleize将整数更改为其“元组”。 例如:

1.Tupleize();
// single
3.Tupleize();
// triple
100.Tupleize();
// centuple

数字1-10、100和1000将转换为“命名”元组(即“单”,“双”等)。 任何其他数字“ n”将转换为“ n元组”。

 

Humanizer 混合到您的框架中以简化您的生活

这只是一个基础,您可以使用它来简化您的日常工作。 例如,在Asp.Net MVC中,我们一直在ViewModel属性上保留Display属性,以便HtmlHelper可以为我们生成正确的标签。 但是,就像枚举一样,在大多数情况下,我们只需要在属性名称中的单词之间留一个空格-那么为什么不使用“ string” .Humanize呢?

您可能会在执行该操作的代码中找到一个Asp.Net MVC示例(尽管该项目已从解决方案文件中排除,从而使nuget包也可用于.Net 3.5)。

这是通过使用名为HumanizerMetadataProvider的自定义DataAnnotationsModelMetadataProvider实现的。 它足够小,可以在这里重复; 所以我们开始:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using Humanizer;

namespace YourApp
{
    public class HumanizerMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        protected override ModelMetadata CreateMetadata(
            IEnumerable<Attribute> attributes,
            Type containerType,
            Func<object> modelAccessor,
            Type modelType,
            string propertyName)
        {
            var propertyAttributes = attributes.ToList();
            var modelMetadata = base.CreateMetadata(propertyAttributes, containerType, modelAccessor, modelType, propertyName);

            if (IsTransformRequired(modelMetadata, propertyAttributes))
                modelMetadata.DisplayName = modelMetadata.PropertyName.Humanize();

            return modelMetadata;
        }

        private static bool IsTransformRequired(ModelMetadata modelMetadata, IList<Attribute> propertyAttributes)
        {
            if (string.IsNullOrEmpty(modelMetadata.PropertyName))
                return false;

            if (propertyAttributes.OfType<DisplayNameAttribute>().Any())
                return false;

            if (propertyAttributes.OfType<DisplayAttribute>().Any())
                return false;

            return true;
        }
    }
}

此类调用基类以提取元数据,然后根据需要使属性名称人性化。 它正在检查属性是否已经具有DisplayName或Display属性,在这种情况下,元数据提供程序将仅接受该属性,而保留该属性。 对于其他属性,它将人性化属性名称。 就这些。

现在,您需要使用Asp.Net MVC注册该元数据提供程序。 确保使用System.Web.Mvc.ModelMetadataProviders,而不使用System.Web.ModelBinding.ModelMetadataProviders:

ModelMetadataProviders.Current = new HumanizerMetadataProvider();

...现在您可以替换:

public class RegisterModel
{
    [Display(Name = "User name")]
    public string UserName { get; set; }

    [Display(Name = "Email address")]
    public string EmailAddress { get; set; }

    [Display(Name = "Confirm password")]
    public string ConfirmPassword { get; set; }
}

public class RegisterModel
{
    public string UserName { get; set; }
    public string EmailAddress { get; set; }
    public string ConfirmPassword { get; set; }
}

 

...,“元数据人性化工具”将负责其余的工作。

无需提及,如果您想为标签加上标题框,则可以使用Transform链接方法:

modelMetadata.DisplayName = modelMetadata.PropertyName.Humanize().Transform(To.TitleCase);

 

已知的安装问题和解决方法

由于CLI工具中的错误,主要的Humanizer软件包及其语言软件包将无法安装。 作为临时解决方法,在修复该错误之前,请改用Humanizer.xproj。 它包含所有语言。

 

 

GitHub地址:https://github.com/Humanizr/Humanizer

posted @ 2020-03-19 11:32  古道轻风  阅读(1785)  评论(0编辑  收藏  举报