rabidus-test/Assets/Plugins/QFSW/Quantum Console/Source/Scripts/Utilities/TextProcessing.cs

215 lines
8.5 KiB
C#

using QFSW.QC.Containers;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QFSW.QC
{
public static class TextProcessing
{
public static readonly char[] DefaultLeftScopers = { '<', '[', '(', '{', '"' };
public static readonly char[] DefaultRightScopers = { '>', ']', ')', '}', '"' };
public static string ReduceScope(this string input, int maxReduction = -1)
{
return input.ReduceScope(DefaultLeftScopers, DefaultRightScopers, maxReduction);
}
public static string ReduceScope(this string input, char leftScoper, char rightScoper, int maxReduction = -1)
{
return input.ReduceScope(leftScoper.AsArraySingle(), rightScoper.AsArraySingle(), maxReduction);
}
public static string ReduceScope<T>(this string input, T leftScopers, T rightScopers, int maxReduction = -1)
where T : IReadOnlyList<char>
{
if (leftScopers.Count != rightScopers.Count)
{
throw new ArgumentException("There must be an equal number of corresponding left and right scopers");
}
if (string.IsNullOrWhiteSpace(input))
{
return string.Empty;
}
string trimmedInput = input.Trim();
if (maxReduction == 0)
{
return trimmedInput;
}
for (int i = 0; i < leftScopers.Count; i++)
{
char leftScoper = leftScopers[i];
char rightScoper = rightScopers[i];
if (leftScoper == rightScoper)
{
string descopedInput = trimmedInput;
bool descoped = false;
while (descopedInput[0] == leftScoper && descopedInput[descopedInput.Length - 1] == rightScoper)
{
descoped = true;
descopedInput = descopedInput.Substring(1, descopedInput.Length - 2).Trim();
if (descopedInput.Length == 0) { break; }
}
for (int j = 0; j < descopedInput.Length; j++)
{
if (descopedInput[j] == leftScoper && (j == 0 || descopedInput[j - 1] != '\\'))
{
descoped = false;
break;
}
}
if (descoped) { return descopedInput.ReduceScope(leftScopers, rightScopers, maxReduction - 1); }
}
else
{
if (trimmedInput[0] == leftScoper && trimmedInput[trimmedInput.Length - 1] == rightScoper)
{
int scope = 1;
for (int j = 1; j < trimmedInput.Length - 1; j++)
{
if (trimmedInput[j] == leftScoper) { scope++; }
else if (trimmedInput[j] == rightScoper) { scope--; }
if (scope == 0)
{
return trimmedInput;
}
}
return trimmedInput.Substring(1, trimmedInput.Length - 2).ReduceScope(leftScopers, rightScopers, maxReduction - 1);
}
}
}
return input;
}
public static string[] SplitScoped(this string input, char splitChar, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, -1, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, int maxCount, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, DefaultLeftScopers, DefaultRightScopers, maxCount, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, char leftScoper, char rightScoper, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, leftScoper, rightScoper, -1, autoReduceScope);
}
public static string[] SplitScoped(this string input, char splitChar, char leftScoper, char rightScoper, int maxCount, bool autoReduceScope = false)
{
return input.SplitScoped(splitChar, leftScoper.AsArraySingle(), rightScoper.AsArraySingle(), maxCount, autoReduceScope);
}
public static string[] SplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers, bool autoReduceScope = false)
where T : IReadOnlyList<char>
{
return input.SplitScoped(splitChar, leftScopers, rightScopers, -1, autoReduceScope);
}
public static string[] SplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers, int maxCount, bool autoReduceScope = false)
where T : IReadOnlyList<char>
{
if (autoReduceScope) { input = input.ReduceScope(leftScopers, rightScopers); }
if (string.IsNullOrWhiteSpace(input)) { return Array.Empty<string>(); }
IEnumerable<int> rawSplitIndices = GetScopedSplitPoints(input, splitChar, leftScopers, rightScopers);
int[] splitIndices;
if (maxCount > 0)
{
splitIndices = rawSplitIndices.Take(maxCount - 1).ToArray();
}
else
{
splitIndices = rawSplitIndices.ToArray();
}
// Return single array when no splits occurred
if (splitIndices.Length == 0)
{
return new[] { input };
}
string[] splitString = new string[splitIndices.Length + 1];
int lastSplitIndex = 0;
for (int i = 0; i < splitIndices.Length; i++)
{
splitString[i] = input.Substring(lastSplitIndex, splitIndices[i] - lastSplitIndex).Trim();
lastSplitIndex = splitIndices[i] + 1;
}
splitString[splitIndices.Length] = input.Substring(lastSplitIndex).Trim();
return splitString;
}
public static IEnumerable<int> GetScopedSplitPoints<T>(string input, char splitChar, T leftScopers, T rightScopers)
where T : IReadOnlyList<char>
{
if (leftScopers.Count != rightScopers.Count)
{
throw new ArgumentException("There must be an equal number of corresponding left and right scopers");
}
int[] scopes = new int[leftScopers.Count];
for (int i = 0; i < input.Length; i++)
{
if (i == 0 || input[i - 1] != '\\')
{
for (int j = 0; j < leftScopers.Count; j++)
{
char leftScoper = leftScopers[j];
char rightScoper = rightScopers[j];
if (input[i] == leftScoper && leftScoper == rightScoper) { scopes[j] = 1 - scopes[j]; }
else if (input[i] == leftScoper) { scopes[j]++; }
else if (input[i] == rightScoper) { scopes[j]--; }
}
}
if (input[i] == splitChar && scopes.All(x => x == 0))
{
yield return i;
}
}
}
public static bool CanSplitScoped(this string input, char splitChar)
{
return input.CanSplitScoped(splitChar, DefaultLeftScopers, DefaultRightScopers);
}
public static bool CanSplitScoped(this string input, char splitChar, char leftScoper, char rightScoper)
{
return input.CanSplitScoped(splitChar, leftScoper.AsArraySingle(), rightScoper.AsArraySingle());
}
public static bool CanSplitScoped<T>(this string input, char splitChar, T leftScopers, T rightScopers)
where T : IReadOnlyList<char>
{
return GetScopedSplitPoints(input, splitChar, leftScopers, rightScopers).Any();
}
public static string UnescapeText(this string input, char escapeChar) { return input.UnescapeText(escapeChar.AsArraySingle()); }
public static string UnescapeText<T>(this string input, T escapeChars)
where T : IReadOnlyCollection<char>
{
foreach (char escapeChar in escapeChars)
{
input = input.Replace($"\\{escapeChar}", escapeChar.ToString());
}
return input;
}
}
}