| | | 1 | | // ----------------------------------------------------------------------- |
| | | 2 | | // <copyright file="InflectorBuilder.cs" company="Stéphane ANDRE"> |
| | | 3 | | // Copyright (c) Stéphane ANDRE. All rights reserved. |
| | | 4 | | // </copyright> |
| | | 5 | | // ----------------------------------------------------------------------- |
| | | 6 | | |
| | | 7 | | using System; |
| | | 8 | | using System.Collections.Generic; |
| | | 9 | | using System.Collections.Immutable; |
| | | 10 | | using System.Globalization; |
| | | 11 | | using System.Text.RegularExpressions; |
| | | 12 | | |
| | | 13 | | namespace MyNet.Globalization.Inflection; |
| | | 14 | | |
| | | 15 | | /// <summary> |
| | | 16 | | /// Builder class for constructing an instance of the <see cref="Inflector"/> class. This builder allows for the additio |
| | | 17 | | /// </summary> |
| | | 18 | | public sealed class InflectorBuilder |
| | | 19 | | { |
| | 27 | 20 | | private readonly List<InflectionRule> _plurals = []; |
| | 27 | 21 | | private readonly List<InflectionRule> _singulars = []; |
| | | 22 | | private readonly HashSet<string> _uncountables; |
| | | 23 | | |
| | | 24 | | /// <summary> |
| | | 25 | | /// Initializes a new instance of the <see cref="InflectorBuilder"/> class with the specified culture. The culture i |
| | | 26 | | /// </summary> |
| | | 27 | | /// <param name="culture">The culture information to use for inflection rules.</param> |
| | | 28 | | /// <exception cref="ArgumentNullException">Thrown when the provided culture is null.</exception> |
| | | 29 | | public InflectorBuilder(CultureInfo culture) |
| | | 30 | | { |
| | 27 | 31 | | ArgumentNullException.ThrowIfNull(culture); |
| | | 32 | | |
| | | 33 | | Culture = culture; |
| | | 34 | | |
| | 27 | 35 | | _uncountables = new(StringComparer.Create(culture, ignoreCase: true)); |
| | 27 | 36 | | } |
| | | 37 | | |
| | | 38 | | /// <summary> |
| | | 39 | | /// Gets the culture associated with this inflector builder. The culture is used to ensure that the inflection rules |
| | | 40 | | /// </summary> |
| | | 41 | | public CultureInfo Culture { get; } |
| | | 42 | | |
| | | 43 | | /// <summary> |
| | | 44 | | /// Adds a pluralization rule to the inflector. The rule consists of a regular expression pattern and a replacement |
| | | 45 | | /// </summary> |
| | | 46 | | /// <param name="pattern">The regular expression pattern to match.</param> |
| | | 47 | | /// <param name="replacement">The replacement string to use when the pattern matches.</param> |
| | | 48 | | /// <exception cref="ArgumentException">Thrown when the provided pattern is null or empty.</exception> |
| | | 49 | | /// <exception cref="ArgumentNullException">Thrown when the provided replacement is null.</exception> |
| | | 50 | | public InflectorBuilder AddPluralRule(string pattern, string replacement) |
| | | 51 | | { |
| | 507 | 52 | | ArgumentException.ThrowIfNullOrEmpty(pattern); |
| | 507 | 53 | | ArgumentNullException.ThrowIfNull(replacement); |
| | | 54 | | |
| | 507 | 55 | | _plurals.Add(CreateRule(pattern, replacement)); |
| | | 56 | | |
| | 507 | 57 | | return this; |
| | | 58 | | } |
| | | 59 | | |
| | | 60 | | /// <summary> |
| | | 61 | | /// Adds a singularization rule to the inflector. The rule consists of a regular expression pattern and a replacemen |
| | | 62 | | /// </summary> |
| | | 63 | | /// <param name="pattern">The regular expression pattern to match.</param> |
| | | 64 | | /// <param name="replacement">The replacement string to use when the pattern matches.</param> |
| | | 65 | | /// <exception cref="ArgumentException">Thrown when the provided pattern is null or empty.</exception> |
| | | 66 | | /// <exception cref="ArgumentNullException">Thrown when the provided replacement is null.</exception> |
| | | 67 | | public InflectorBuilder AddSingularRule(string pattern, string replacement) |
| | | 68 | | { |
| | 519 | 69 | | ArgumentException.ThrowIfNullOrEmpty(pattern); |
| | 519 | 70 | | ArgumentNullException.ThrowIfNull(replacement); |
| | | 71 | | |
| | 519 | 72 | | _singulars.Add(CreateRule(pattern, replacement)); |
| | | 73 | | |
| | 519 | 74 | | return this; |
| | | 75 | | } |
| | | 76 | | |
| | | 77 | | /// <summary> |
| | | 78 | | /// Adds an irregular inflection rule for a word, specifying both its singular and plural forms. This method allows |
| | | 79 | | /// </summary> |
| | | 80 | | /// <param name="singular">The singular form of the word.</param> |
| | | 81 | | /// <param name="plural">The plural form of the word.</param> |
| | | 82 | | /// <param name="matchEnding">Indicates whether the rule should match the word at the end of longer words.</param> |
| | | 83 | | /// <exception cref="ArgumentException">Thrown when the provided singular or plural form is null or empty.</exceptio |
| | | 84 | | public InflectorBuilder AddIrregular(string singular, string plural, bool matchEnding = true) |
| | | 85 | | { |
| | 345 | 86 | | ArgumentException.ThrowIfNullOrEmpty(singular); |
| | 345 | 87 | | ArgumentException.ThrowIfNullOrEmpty(plural); |
| | | 88 | | |
| | 345 | 89 | | if (matchEnding) |
| | | 90 | | { |
| | 312 | 91 | | AddPluralRule($"({singular[0]}){singular[1..]}$", $"$1{plural[1..]}"); |
| | 312 | 92 | | AddSingularRule($"({plural[0]}){plural[1..]}$", $"$1{singular[1..]}"); |
| | | 93 | | } |
| | | 94 | | else |
| | | 95 | | { |
| | 33 | 96 | | AddPluralRule($"^{singular}$", plural); |
| | 33 | 97 | | AddSingularRule($"^{plural}$", singular); |
| | | 98 | | } |
| | | 99 | | |
| | 345 | 100 | | return this; |
| | | 101 | | } |
| | | 102 | | |
| | | 103 | | /// <summary> |
| | | 104 | | /// Adds an uncountable word to the inflector. Uncountable words are those that do not have a plural form and should |
| | | 105 | | /// </summary> |
| | | 106 | | /// <param name="word">The uncountable word to add.</param> |
| | | 107 | | /// <exception cref="ArgumentException">Thrown when the provided word is null or empty.</exception> |
| | | 108 | | public InflectorBuilder AddUncountable(string word) |
| | | 109 | | { |
| | 243 | 110 | | ArgumentException.ThrowIfNullOrEmpty(word); |
| | | 111 | | |
| | 243 | 112 | | _uncountables.Add(word); |
| | | 113 | | |
| | 243 | 114 | | return this; |
| | | 115 | | } |
| | | 116 | | |
| | | 117 | | /// <summary> |
| | | 118 | | /// Builds and returns an instance of the <see cref="Inflector"/> class based on the rules that have been added to t |
| | | 119 | | /// </summary> |
| | | 120 | | /// <returns>An instance of the <see cref="Inflector"/> class.</returns> |
| | 27 | 121 | | public Inflector Build() => new(Culture, new() |
| | 27 | 122 | | { |
| | 27 | 123 | | Plurals = [.._plurals], |
| | 27 | 124 | | Singulars = [.._singulars], |
| | 27 | 125 | | Uncountables = _uncountables.ToImmutableHashSet(_uncountables.Comparer) |
| | 27 | 126 | | }); |
| | | 127 | | |
| | | 128 | | /// <summary> |
| | | 129 | | /// Creates an inflection rule based on the provided regular expression pattern and replacement string. The method c |
| | | 130 | | /// </summary> |
| | | 131 | | /// <param name="pattern">The regular expression pattern to match.</param> |
| | | 132 | | /// <param name="replacement">The replacement string to use when the pattern matches.</param> |
| | | 133 | | /// <returns>An inflection rule based on the provided pattern and replacement.</returns> |
| | | 134 | | private static InflectionRule CreateRule(string pattern, string replacement) |
| | 1026 | 135 | | => new( |
| | 1026 | 136 | | new(pattern, RegexOptions.None | RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvar |
| | 1026 | 137 | | replacement); |
| | | 138 | | } |
| | | 139 | | |