diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 56a0c62f8..79f42dc1d 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -16,7 +16,7 @@ variables:
steps:
- task: DotNetCoreInstaller@0
inputs:
- version: '2.1.500'
+ version: '2.2.105'
- task: DotNetCoreCLI@2
inputs:
diff --git a/src/Directory.build.props b/src/Directory.build.props
index 84d7166db..f95fea5f9 100644
--- a/src/Directory.build.props
+++ b/src/Directory.build.props
@@ -7,7 +7,7 @@
-
+
diff --git a/src/Humanizer.Tests.Shared/ArticlePrefixSortTests.cs b/src/Humanizer.Tests.Shared/ArticlePrefixSortTests.cs
new file mode 100644
index 000000000..f2d3e1450
--- /dev/null
+++ b/src/Humanizer.Tests.Shared/ArticlePrefixSortTests.cs
@@ -0,0 +1,23 @@
+using System;
+using Xunit;
+
+namespace Humanizer.Tests
+{
+ public class ArticlePrefixSortTests
+ {
+ [Theory]
+ [InlineData(new[] { "Ant", "The Theater", "The apple", "Fox", "Bear" }, new[] { "Ant", "The apple", "Bear", "Fox", "The Theater" })]
+ public void SortStringArrayIgnoringArticlePrefixes(string[] input, string[] expectedOutput)
+ {
+ Assert.Equal(expectedOutput, EnglishArticle.PrependArticleSuffix(EnglishArticle.AppendArticlePrefix(input)));
+ }
+
+ [Fact]
+ public void An_Empty_String_Array_Throws_ArgumentOutOfRangeException()
+ {
+ string[] items = { };
+ void action() => EnglishArticle.AppendArticlePrefix(items);
+ Assert.Throws(action);
+ }
+ }
+}
diff --git a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
index 005aac23c..e073cc484 100644
--- a/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
+++ b/src/Humanizer.Tests/ApiApprover/PublicApiApprovalTest.approve_public_api.approved.txt
@@ -59,6 +59,16 @@ namespace Humanizer.Bytes
public static Humanizer.Bytes.ByteSize FromMegabytes(double value) { }
public static Humanizer.Bytes.ByteSize FromTerabytes(double value) { }
public override int GetHashCode() { }
+ public static Humanizer.Bytes.ByteSize +(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static Humanizer.Bytes.ByteSize --(Humanizer.Bytes.ByteSize b) { }
+ public static bool ==(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static bool >(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static bool >=(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static Humanizer.Bytes.ByteSize ++(Humanizer.Bytes.ByteSize b) { }
+ public static bool !=(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static bool <(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static bool <=(Humanizer.Bytes.ByteSize b1, Humanizer.Bytes.ByteSize b2) { }
+ public static Humanizer.Bytes.ByteSize -(Humanizer.Bytes.ByteSize b) { }
public static Humanizer.Bytes.ByteSize Parse(string s) { }
public Humanizer.Bytes.ByteSize Subtract(Humanizer.Bytes.ByteSize bs) { }
public string ToFullWords() { }
@@ -150,6 +160,17 @@ namespace Humanizer
public static string ToOrdinalWords(this System.DateTime input) { }
public static string ToOrdinalWords(this System.DateTime input, Humanizer.GrammaticalCase grammaticalCase) { }
}
+ public class static EnglishArticle
+ {
+ public static string[] AppendArticlePrefix(string[] items) { }
+ public static string[] PrependArticleSuffix(string[] appended) { }
+ }
+ public enum EnglishArticles
+ {
+ A = 0,
+ An = 1,
+ The = 2,
+ }
public class static EnumDehumanizeExtensions
{
public static TTargetEnum DehumanizeTo(this string input)
diff --git a/src/Humanizer.Tests/Humanizer.Tests.csproj b/src/Humanizer.Tests/Humanizer.Tests.csproj
index e8e2a266a..385809766 100644
--- a/src/Humanizer.Tests/Humanizer.Tests.csproj
+++ b/src/Humanizer.Tests/Humanizer.Tests.csproj
@@ -7,16 +7,16 @@
$(DefineConstants);NETFX_CORE
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/src/Humanizer.sln b/src/Humanizer.sln
index 05683f108..524773fff 100644
--- a/src/Humanizer.sln
+++ b/src/Humanizer.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2010
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.28711.165
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Humanizer.Tests", "Humanizer.Tests\Humanizer.Tests.csproj", "{F886A8DA-3EFC-4A89-91DD-06FAF13DA172}"
EndProject
@@ -12,18 +12,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\.editorconfig = ..\.editorconfig
..\.gitattributes = ..\.gitattributes
..\.gitignore = ..\.gitignore
+ Directory.build.props = Directory.build.props
..\NuSpecs\Humanizer.Core.nuspec = ..\NuSpecs\Humanizer.Core.nuspec
..\NuSpecs\Humanizer.nuspec = ..\NuSpecs\Humanizer.nuspec
..\LICENSE = ..\LICENSE
..\readme.md = ..\readme.md
..\release_notes.md = ..\release_notes.md
+ ..\version.json = ..\version.json
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{97AAE24D-0488-42AE-A585-86D882F23D5F}"
ProjectSection(SolutionItems) = preProject
- ..\.vsts-ci.yml = ..\.vsts-ci.yml
- ..\.vsts-pr.yml = ..\.vsts-pr.yml
- ..\.vsts-shared.yml = ..\.vsts-shared.yml
+ ..\azure-pipelines.yml = ..\azure-pipelines.yml
..\build.cmd = ..\build.cmd
Humanizer.ruleset = Humanizer.ruleset
EndProjectSection
diff --git a/src/Humanizer/ArticlePrefixSort.cs b/src/Humanizer/ArticlePrefixSort.cs
new file mode 100644
index 000000000..961792624
--- /dev/null
+++ b/src/Humanizer/ArticlePrefixSort.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace Humanizer
+{
+ ///
+ /// Contains methods for removing, appending and prepending article prefixes for sorting strings ignoring the article.
+ ///
+ public static class EnglishArticle
+ {
+ ///
+ /// Removes the prefixed article and appends it to the same string.
+ ///
+ /// The input array of strings
+ /// Sorted string array
+ public static string[] AppendArticlePrefix(string[] items)
+ {
+ if (items.Length == 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(items));
+ }
+
+ var regex = new Regex("^((The)|(the)|(a)|(A)|(An)|(an))\\s\\w+");
+ var transformed = new string[items.Length];
+
+ for (var i = 0; i < items.Length; i++)
+ {
+ if (regex.IsMatch(items[i]))
+ {
+ var article = items[i].Substring(0, items[i].IndexOf(" ", StringComparison.CurrentCulture));
+ var removed = items[i].Remove(0, items[i].IndexOf(" ", StringComparison.CurrentCulture));
+ var appended = $"{removed} {article}";
+ transformed[i] = appended.Trim();
+ }
+ else
+ {
+ transformed[i] = items[i].Trim();
+ }
+ }
+ Array.Sort(transformed);
+ return transformed;
+ }
+
+ ///
+ /// Removes the previously appended article and prepends it to the same string.
+ ///
+ /// Sorted string array
+ /// String array
+ public static string[] PrependArticleSuffix(string[] appended)
+ {
+ var inserted = new string[appended.Length];
+
+ for (var i = 0; i < appended.Length; i++)
+ {
+ string suffix;
+ string original;
+ if (appended[i].EndsWith(EnglishArticles.The.ToString()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" The", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else if (appended[i].EndsWith(EnglishArticles.A.ToString()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" A", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else if (appended[i].EndsWith(EnglishArticles.An.ToString()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" An", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else if (appended[i].EndsWith(EnglishArticles.A.ToString().ToLowerInvariant()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" a", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else if (appended[i].EndsWith(EnglishArticles.An.ToString().ToLowerInvariant()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" an", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else if (appended[i].EndsWith(EnglishArticles.The.ToString().ToLowerInvariant()))
+ {
+ suffix = appended[i].Substring(appended[i].IndexOf(" the", StringComparison.CurrentCulture));
+ original = ToOriginalFormat(appended, suffix, i);
+ inserted[i] = original;
+ }
+ else
+ {
+ inserted[i] = appended[i];
+ }
+ }
+ return inserted;
+ }
+
+ private static string ToOriginalFormat(string[] appended, string suffix, int i)
+ {
+ var insertion = appended[i].Remove(appended[i].IndexOf(suffix, StringComparison.CurrentCulture));
+ var original = $"{suffix} {insertion}";
+ return original.Trim();
+ }
+ }
+}
diff --git a/src/Humanizer/Articles.cs b/src/Humanizer/Articles.cs
new file mode 100644
index 000000000..290e67378
--- /dev/null
+++ b/src/Humanizer/Articles.cs
@@ -0,0 +1,21 @@
+namespace Humanizer
+{
+ ///
+ /// Definite and Indefinite English Articles
+ ///
+ public enum EnglishArticles
+ {
+ ///
+ /// A
+ ///
+ A,
+ ///
+ /// An
+ ///
+ An,
+ ///
+ /// The
+ ///
+ The
+ }
+}
diff --git a/src/Humanizer/Humanizer.csproj b/src/Humanizer/Humanizer.csproj
index 2e9a2bfc3..1e45dcc4c 100644
--- a/src/Humanizer/Humanizer.csproj
+++ b/src/Humanizer/Humanizer.csproj
@@ -6,7 +6,7 @@
https://github.com/Humanizr/Humanizer
2.12
A micro-framework that turns your normal strings, type names, enum fields, date fields ETC into a human friendly format
- Copyright © 2012-2018 Mehdi Khalili
+ Copyright © 2012-2019 .NET Foundation and Contributors
Humanizer ($(TargetFramework))
true
true
diff --git a/version.json b/version.json
index be15d5463..c5578c950 100644
--- a/version.json
+++ b/version.json
@@ -1,5 +1,5 @@
{
- "version": "2.5",
+ "version": "2.6",
"publicReleaseRefSpec": [
"^refs/heads/master$", // we release out of master
"^refs/heads/rel/v\\d+\\.\\d+" // we also release branches starting with rel/vN.N