99 lines
3.6 KiB
C#
99 lines
3.6 KiB
C#
using FileManager.NamingTemplate;
|
||
using NameParser;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text.RegularExpressions;
|
||
|
||
#nullable enable
|
||
namespace LibationFileManager
|
||
{
|
||
internal partial class NameListFormat
|
||
{
|
||
public static string Formatter(ITemplateTag _, IEnumerable<string>? names, string formatString)
|
||
{
|
||
if (names is null) return "";
|
||
|
||
var humanNames = names.Select(n => new HumanName(RemoveSuffix(n), Prefer.FirstOverPrefix));
|
||
|
||
var sortedNames = Sort(humanNames, formatString);
|
||
var nameFormatString = Format(formatString, defaultValue: "{T} {F} {M} {L} {S}");
|
||
var separatorString = Separator(formatString, defaultValue: ", ");
|
||
var maxNames = Max(formatString, defaultValue: humanNames.Count());
|
||
|
||
var formattedNames = string.Join(separatorString, sortedNames.Take(maxNames).Select(n => FormatName(n, nameFormatString)));
|
||
|
||
while (formattedNames.Contains(" "))
|
||
formattedNames = formattedNames.Replace(" ", " ");
|
||
|
||
return formattedNames;
|
||
}
|
||
|
||
private static string RemoveSuffix(string namesString)
|
||
{
|
||
namesString = namesString.Replace('’', '\'').Replace(" - Ret.", ", Ret.");
|
||
int dashIndex = namesString.IndexOf(" - ");
|
||
return (dashIndex > 0 ? namesString[..dashIndex] : namesString).Trim();
|
||
}
|
||
|
||
private static IEnumerable<HumanName> Sort(IEnumerable<HumanName> humanNames, string formatString)
|
||
{
|
||
var sortMatch = SortRegex().Match(formatString);
|
||
return
|
||
sortMatch.Success
|
||
? sortMatch.Groups[1].Value == "F" ? humanNames.OrderBy(n => n.First)
|
||
: sortMatch.Groups[1].Value == "M" ? humanNames.OrderBy(n => n.Middle)
|
||
: sortMatch.Groups[1].Value == "L" ? humanNames.OrderBy(n => n.Last)
|
||
: humanNames
|
||
: humanNames;
|
||
}
|
||
|
||
private static string Format(string formatString, string defaultValue)
|
||
{
|
||
var formatMatch = FormatRegex().Match(formatString);
|
||
return formatMatch.Success ? formatMatch.Groups[1].Value : defaultValue;
|
||
}
|
||
|
||
private static string Separator(string formatString, string defaultValue)
|
||
{
|
||
var separatorMatch = SeparatorRegex().Match(formatString);
|
||
return separatorMatch.Success ? separatorMatch.Groups[1].Value : defaultValue;
|
||
}
|
||
|
||
private static int Max(string formatString, int defaultValue)
|
||
{
|
||
var maxMatch = MaxRegex().Match(formatString);
|
||
return maxMatch.Success && int.TryParse(maxMatch.Groups[1].Value, out var max) ? int.Max(1, max) : defaultValue;
|
||
}
|
||
|
||
private static string FormatName(HumanName humanName, string nameFormatString)
|
||
{
|
||
//Single-word names parse as first names. Use it as last name.
|
||
var lastName = string.IsNullOrWhiteSpace(humanName.Last) ? humanName.First : humanName.Last;
|
||
|
||
nameFormatString
|
||
= nameFormatString
|
||
.Replace("{T}", "{0}")
|
||
.Replace("{F}", "{1}")
|
||
.Replace("{M}", "{2}")
|
||
.Replace("{L}", "{3}")
|
||
.Replace("{S}", "{4}");
|
||
|
||
return string.Format(nameFormatString, humanName.Title, humanName.First, humanName.Middle, lastName, humanName.Suffix).Trim();
|
||
}
|
||
|
||
/// <summary> Sort must have exactly one of the characters F, M, or L </summary>
|
||
[GeneratedRegex(@"[Ss]ort\(\s*?([FML])\s*?\)")]
|
||
private static partial Regex SortRegex();
|
||
/// <summary> Format must have at least one of the string {T}, {F}, {M}, {L}, or {S} </summary>
|
||
[GeneratedRegex(@"[Ff]ormat\((.*?(?:{[TFMLS]})+.*?)\)")]
|
||
private static partial Regex FormatRegex();
|
||
/// <summary> Separator can be anything </summary>
|
||
[GeneratedRegex(@"[Ss]eparator\((.*?)\)")]
|
||
private static partial Regex SeparatorRegex();
|
||
/// <summary> Max must have a 1 or 2-digit number </summary>
|
||
[GeneratedRegex(@"[Mm]ax\(\s*?(\d{1,2})\s*?\)")]
|
||
private static partial Regex MaxRegex();
|
||
}
|
||
}
|