Files
OldThink/Content.Server/_White/TTS/TTSSystem.Sanitize.cs

289 lines
9.2 KiB
C#
Raw Normal View History

using System.Text;
using System.Text.RegularExpressions;
using Content.Server.Chat.Systems;
namespace Content.Server._White.TTS;
// ReSharper disable once InconsistentNaming
public sealed partial class TTSSystem
{
private void OnTransformSpeech(TransformSpeechEvent args)
{
if (!_isEnabled)
return;
args.Message = args.Message.Replace("+", "");
}
private string Sanitize(string text)
{
text = text.Trim();
text = Regex.Replace(text, @"Ё", "Е");
2023-10-28 15:49:45 +03:00
text = Regex.Replace(text, @"[^a-zA-Zа-яА-ЯёЁ0-9,\-,+, ,?,!,.]", "");
text = Regex.Replace(text, @"[a-zA-Z]", ReplaceLat2Cyr, RegexOptions.Multiline | RegexOptions.IgnoreCase);
text = Regex.Replace(text, @"(?<![a-zA-Zа-яёА-ЯЁ])[a-zA-Zа-яёА-ЯЁ]+?(?![a-zA-Zа-яёА-ЯЁ])", ReplaceMatchedWord, RegexOptions.Multiline | RegexOptions.IgnoreCase);
text = Regex.Replace(text, @"(?<=[1-90])(\.|,)(?=[1-90])", " целых ");
text = Regex.Replace(text, @"\d+", ReplaceWord2Num);
text = text.Trim();
return text;
}
private string ReplaceLat2Cyr(Match oneChar)
{
if (ReverseTranslit.TryGetValue(oneChar.Value.ToLower(), out var replace))
return replace;
return oneChar.Value;
}
private string ReplaceMatchedWord(Match word)
{
if (WordReplacement.TryGetValue(word.Value.ToLower(), out var replace))
return replace;
return word.Value;
}
private string ReplaceWord2Num(Match word)
{
if (!long.TryParse(word.Value, out var number))
return word.Value;
return NumberConverter.NumberToText(number);
}
private static readonly IReadOnlyDictionary<string, string> WordReplacement =
new Dictionary<string, string>()
{
{"нт", "Эн Тэ"},
{"смо", "Эс Мэ О"},
{"гп", "Гэ Пэ"},
{"рд", "Эр Дэ"},
{"гсб", "Гэ Эс Бэ"},
{"гв", "Гэ Вэ"},
{"нр", "Эн Эр"},
{"срп", "Эс Эр Пэ"},
{"цк", "Цэ Каа"},
{"рнд", "Эр Эн Дэ"},
{"сб", "Эс Бэ"},
{"рцд", "Эр Цэ Дэ"},
{"брпд", "Бэ Эр Пэ Дэ"},
{"рпд", "Эр Пэ Дэ"},
{"рпед", "Эр Пед"},
{"тсф", "Тэ Эс Эф"},
{"срт", "Эс Эр Тэ"},
{"обр", "О Бэ Эр"},
{"кпк", "Кэ Пэ Каа"},
{"пда", "Пэ Дэ А"},
{"id", "Ай Ди"},
{"мщ", "Эм Ще"},
{"вт", "Вэ Тэ"},
{"ерп", "Йе Эр Пэ"},
{"се", "Эс Йе"},
{"апц", "А Пэ Цэ"},
{"лкп", "Эл Ка Пэ"},
{"см", "Эс Эм"},
{"ека", "Йе Ка"},
{"ка", "Кэ А"},
{"бса", "Бэ Эс Аа"},
{"тк", "Тэ Ка"},
{"бфл", "Бэ Эф Эл"},
{"бщ", "Бэ Щэ"},
{"кк", "Кэ Ка"},
{"ск", "Эс Ка"},
{"зк", "Зэ Ка"},
{"ерт", "Йе Эр Тэ"},
{"вкд", "Вэ Ка Дэ"},
{"нтр", "Эн Тэ Эр"},
{"пнт", "Пэ Эн Тэ"},
{"авд", "А Вэ Дэ"},
{"пнв", "Пэ Эн Вэ"},
{"ссд", "Эс Эс Дэ"},
{"кпб", "Кэ Пэ Бэ"},
{"сссп", "Эс Эс Эс Пэ"},
{"крб", "Ка Эр Бэ"},
{"бд", "Бэ Дэ"},
{"сст", "Эс Эс Тэ"},
{"скс", "Эс Ка Эс"},
{"икн", Ка Эн"},
{"нсс", "Эн Эс Эс"},
{"емп", "Йе Эм Пэ"},
{"бс", "Бэ Эс"},
{"цкс", "Цэ Ка Эс"},
{"срд", "Эс Эр Дэ"},
{"жпс", "Джи Пи Эс"},
{"gps", "Джи Пи Эс"},
{"ннксс", "Эн Эн Ка Эс Эс"},
{"ss", "Эс Эс"},
{"сс", "Эс Эс"},
{"тесла", "тэсла"},
{"трейзен", "трэйзэн"},
{"нанотрейзен", "нанотрэйзэн"},
{"рпзд", "Эр Пэ Зэ Дэ"},
{"кз", "Кэ Зэ"},
};
private static readonly IReadOnlyDictionary<string, string> ReverseTranslit =
new Dictionary<string, string>()
{
{"a", "а"},
{"b", "б"},
{"v", "в"},
{"g", "г"},
{"d", "д"},
{"e", "е"},
{"je", "ё"},
{"zh", "ж"},
{"z", "з"},
{"i", "и"},
{"y", "й"},
{"k", "к"},
{"l", "л"},
{"m", "м"},
{"n", "н"},
{"o", "о"},
{"p", "п"},
{"r", "р"},
{"s", "с"},
{"t", "т"},
{"u", "у"},
{"f", "ф"},
{"h", "х"},
{"c", "ц"},
{"x", "кс"},
{"ch", "ч"},
{"sh", "ш"},
{"jsh", "щ"},
{"hh", "ъ"},
{"ih", "ы"},
{"jh", "ь"},
{"eh", "э"},
{"ju", "ю"},
{"ja", "я"},
};
}
// Source: https://codelab.ru/s/csharp/digits2phrase
public static class NumberConverter
{
private static readonly string[] Frac20Male =
{
"", "один", "два", "три", "четыре", "пять", "шесть",
"семь", "восемь", "девять", "десять", "одиннадцать",
"двенадцать", "тринадцать", "четырнадцать", "пятнадцать",
"шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"
};
private static readonly string[] Frac20Female =
{
"", "одна", "две", "три", "четыре", "пять", "шесть",
"семь", "восемь", "девять", "десять", "одиннадцать",
"двенадцать", "тринадцать", "четырнадцать", "пятнадцать",
"шестнадцать", "семнадцать", "восемнадцать", "девятнадцать"
};
private static readonly string[] Hunds =
{
"", "сто", "двести", "триста", "четыреста",
"пятьсот", "шестьсот", "семьсот", "восемьсот", "девятьсот"
};
private static readonly string[] Tens =
{
"", "десять", "двадцать", "тридцать", "сорок", "пятьдесят",
"шестьдесят", "семьдесят", "восемьдесят", "девяносто"
};
public static string NumberToText(long value, bool male = true)
{
if (value >= (long)Math.Pow(10, 15))
return String.Empty;
if (value == 0)
return "ноль";
var str = new StringBuilder();
if (value < 0)
{
str.Append("минус");
value = -value;
}
value = AppendPeriod(value, 1000000000000, str, "триллион", "триллиона", "триллионов", true);
value = AppendPeriod(value, 1000000000, str, "миллиард", "миллиарда", "миллиардов", true);
value = AppendPeriod(value, 1000000, str, "миллион", "миллиона", "миллионов", true);
value = AppendPeriod(value, 1000, str, "тысяча", "тысячи", "тысяч", false);
var hundreds = (int)(value / 100);
if (hundreds != 0)
AppendWithSpace(str, Hunds[hundreds]);
var less100 = (int)(value % 100);
var frac20 = male ? Frac20Male : Frac20Female;
if (less100 < 20)
AppendWithSpace(str, frac20[less100]);
else
{
var tens = less100 / 10;
AppendWithSpace(str, Tens[tens]);
var less10 = less100 % 10;
if (less10 != 0)
str.Append(" " + frac20[less100%10]);
}
return str.ToString();
}
private static void AppendWithSpace(StringBuilder stringBuilder, string str)
{
if (stringBuilder.Length > 0)
stringBuilder.Append(" ");
stringBuilder.Append(str);
}
private static long AppendPeriod(
long value,
long power,
StringBuilder str,
string declension1,
string declension2,
string declension5,
bool male)
{
var thousands = (int)(value / power);
if (thousands > 0)
{
AppendWithSpace(str, NumberToText(thousands, male, declension1, declension2, declension5));
return value % power;
}
return value;
}
private static string NumberToText(
long value,
bool male,
string valueDeclensionFor1,
string valueDeclensionFor2,
string valueDeclensionFor5)
{
return
NumberToText(value, male)
+ " "
+ GetDeclension((int)(value % 10), valueDeclensionFor1, valueDeclensionFor2, valueDeclensionFor5);
}
private static string GetDeclension(int val, string one, string two, string five)
{
var t = (val % 100 > 20) ? val % 10 : val % 20;
switch (t)
{
case 1:
return one;
case 2:
case 3:
case 4:
return two;
default:
return five;
}
}
}