2023-02-16 12:57:06 +00:00
|
|
|
using System.Globalization;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using static System.Math;
|
|
|
|
|
|
|
|
namespace InnovEnergy.Lib.Utils;
|
|
|
|
|
|
|
|
public static class StringUtils
|
|
|
|
{
|
|
|
|
public static String AppendPath(this String left, String right)
|
|
|
|
{
|
|
|
|
return left.TrimEnd('/') + '/' + right.TrimStart('/');
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String RemoveSuffix(this String s, String suffix)
|
|
|
|
{
|
|
|
|
return s.Substring(0, s.LastIndexOf(suffix, StringComparison.Ordinal));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String SafeToString(this Object? o)
|
|
|
|
{
|
|
|
|
return o?.ToString() ?? "<null>";
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Int32 NumberOfLines(this String s)
|
|
|
|
{
|
|
|
|
return s.Split(new[] {Environment.NewLine}, StringSplitOptions.None).Length;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String NewLineBefore(this String s)
|
|
|
|
{
|
|
|
|
return Environment.NewLine + s;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AddTitle(this String s, String title)
|
|
|
|
{
|
|
|
|
return title.Underline() + s;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Underline(this String s)
|
|
|
|
{
|
|
|
|
return s.NewLine() + "".PadRight(s.Length, '-').NewLine(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean IsNullOrEmpty(this String? s)
|
|
|
|
{
|
|
|
|
return String.IsNullOrEmpty(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean IsNullOrWhiteSpace(this String? s)
|
|
|
|
{
|
|
|
|
return String.IsNullOrWhiteSpace(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Format(this Object value, String fmt)
|
|
|
|
{
|
|
|
|
return String.Format(fmt, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String NewLine(this String s)
|
|
|
|
{
|
|
|
|
return s + Environment.NewLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String NewLine(this String s, Int32 number)
|
|
|
|
{
|
|
|
|
return Enumerable
|
|
|
|
.Repeat(Environment.NewLine, number)
|
|
|
|
.Aggregate(s, (a, b) => a + b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String Append(this String s, String other)
|
|
|
|
{
|
|
|
|
return s + other;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String SurroundWith(this String s, String beforeAfter)
|
|
|
|
{
|
|
|
|
return beforeAfter + s + beforeAfter;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String SurroundWith(this String s, String before, String after)
|
|
|
|
{
|
|
|
|
return before + s + after;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String ShellSingleQuote(this String s)
|
|
|
|
{
|
|
|
|
return $"'{s.Replace("'", @"'\''")}'";
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: review
|
|
|
|
public static String Quote(this String s)
|
|
|
|
{
|
|
|
|
return s.Replace(@"\", @"\\")
|
|
|
|
.Replace("\"", "\\\"")
|
|
|
|
.SurroundWith("\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Join(this String separator, params Object[] objects)
|
|
|
|
{
|
|
|
|
return String.Join(separator, objects);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Join(this IEnumerable<String> strings)
|
|
|
|
{
|
|
|
|
return String.Join("", strings);
|
|
|
|
}
|
|
|
|
|
2023-05-18 08:45:44 +00:00
|
|
|
public static String JoinWith(this IEnumerable<String?> strings, String separator)
|
2023-02-16 12:57:06 +00:00
|
|
|
{
|
|
|
|
return String.Join(separator, strings);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String Indent(this String text)
|
|
|
|
{
|
|
|
|
return " ".SideBySideWith(text, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Indent(this String text, Int32 amount)
|
|
|
|
{
|
|
|
|
return text.Indent("".PadLeft(amount));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Indent(this String text, String indent)
|
|
|
|
{
|
2023-06-13 11:04:07 +00:00
|
|
|
return Enumerable
|
|
|
|
.Repeat(indent, text.SplitLines().Count)
|
|
|
|
.JoinLines()
|
|
|
|
.SideBySideWith(text, "");
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static IReadOnlyList<String> SplitLines(this String s)
|
|
|
|
{
|
|
|
|
return s.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String AlignLeft(this String s, Int32 width = 0)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var w = Max(lines.Max(l => l.Length), width);
|
|
|
|
|
|
|
|
return lines
|
|
|
|
.Select(l => l.PadRight(w))
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AlignRight(this String s, Int32 width = 0)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var w = Max(lines.Max(l => l.Length), width);
|
|
|
|
|
|
|
|
return lines
|
|
|
|
.Select(l => l.PadLeft(w))
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AlignCenterHorizontal(this String s, Int32 width = 0)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var w = Max(lines.Max(l => l.Length), width);
|
|
|
|
|
|
|
|
return lines
|
|
|
|
.Select(l => l.PadLeft((w + l.Length) / 2).PadRight(w))
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AlignTop(this String s, Int32 height)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var padding = Enumerable.Repeat("", Max(height - lines.Count, 0));
|
|
|
|
|
|
|
|
return lines
|
|
|
|
.Concat(padding)
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AlignBottom(this String s, Int32 height)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var padding = Enumerable.Repeat("", Max(height - lines.Count, 0));
|
|
|
|
|
|
|
|
return padding
|
|
|
|
.Concat(lines)
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AlignCenterVertical(this String s, Int32 height)
|
|
|
|
{
|
|
|
|
var lines = s.SplitLines();
|
|
|
|
var nPadding = Max(height - lines.Count, 0);
|
|
|
|
var paddingTop = Enumerable.Repeat("", nPadding/2);
|
|
|
|
var paddingBottom = Enumerable.Repeat("", nPadding - nPadding / 2);
|
|
|
|
|
|
|
|
return paddingTop
|
|
|
|
.Concat(lines)
|
|
|
|
.Concat(paddingBottom)
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String SideBySideWith(this String left, String right, String separator = " ")
|
|
|
|
{
|
|
|
|
var leftLines = left.SplitLines();
|
|
|
|
var rightLines = right.SplitLines();
|
|
|
|
|
|
|
|
var leftWidth = left.Width();
|
|
|
|
|
|
|
|
var nLines = Max(leftLines.Count, rightLines.Count);
|
|
|
|
|
|
|
|
var leftPadded = leftLines .PadEnd(nLines, "").Select(l => l.PadRight(leftWidth));
|
|
|
|
var rightPadded = rightLines.PadEnd(nLines, "");
|
|
|
|
|
|
|
|
return Enumerable
|
|
|
|
.Zip(leftPadded, rightPadded, (l, r) => String.Join(separator, l, r))
|
|
|
|
.JoinLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static Int32 Width(this String str)
|
|
|
|
{
|
|
|
|
return str.SplitLines().Max(l => l.Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Int32 Height(this String str)
|
|
|
|
{
|
|
|
|
return str.SplitLines().Count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String Join(this ITuple tuple)
|
|
|
|
{
|
|
|
|
return tuple.JoinWith("");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String JoinWith(this ITuple tuple, String separator)
|
|
|
|
{
|
|
|
|
return tuple
|
|
|
|
.ToEnumerable()
|
|
|
|
.Select(t => t.SafeToString())
|
|
|
|
.JoinWith(separator);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String JoinWith<T>(this IEnumerable<T> args, String separator)
|
|
|
|
{
|
|
|
|
return String.Join(separator, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static IEnumerable<String> GetLinesStartingWith(this IEnumerable<String> lines, String prefix)
|
|
|
|
{
|
|
|
|
return lines.Where(l => l.StartsWith(prefix));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String GetLineStartingWith(this IEnumerable<String> lines, String prefix)
|
|
|
|
{
|
|
|
|
return lines
|
|
|
|
.GetLinesStartingWith(prefix)
|
|
|
|
.Single();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static Boolean EndsWith(this String str, Char c)
|
|
|
|
{
|
|
|
|
if (str.Length <= 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return str[^1] == c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String AfterFirst(this String str, Char separator)
|
|
|
|
{
|
|
|
|
return str.Substring(str.IndexOf(separator) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String AfterLast(this String str, Char separator)
|
|
|
|
{
|
|
|
|
return str.Substring(str.LastIndexOf(separator) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String UntilLast(this String str, Char separator)
|
|
|
|
{
|
|
|
|
var i = str.LastIndexOf(separator);
|
|
|
|
|
|
|
|
return i >= 0
|
|
|
|
? str[..i]
|
|
|
|
: str;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String UntilFirst(this String str, Char separator)
|
|
|
|
{
|
|
|
|
var i = str.IndexOf(separator);
|
|
|
|
|
|
|
|
return i >= 0
|
|
|
|
? str[..i]
|
|
|
|
: str;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean Contains(this String? str, String value, CompareOptions compareOptions)
|
|
|
|
{
|
|
|
|
return Contains(str, value, compareOptions, CultureInfo.InvariantCulture);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean Contains(this String? str, String value, CompareOptions compareOptions, CultureInfo culture)
|
|
|
|
{
|
|
|
|
return str is not null && culture.CompareInfo.IndexOf(str, value, compareOptions) != -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String NewLine(this Object s)
|
|
|
|
{
|
|
|
|
return s + Environment.NewLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String Spaces(this String s, Int32 count = 4)
|
|
|
|
{
|
|
|
|
return s.PadRight(s.Length + count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String JoinNonEmptyLines(this IEnumerable<String> lines)
|
|
|
|
{
|
|
|
|
return String.Join(Environment.NewLine, lines.Unless(String.IsNullOrWhiteSpace));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String JoinLines(this IEnumerable<String> lines)
|
|
|
|
{
|
|
|
|
return String.Join(Environment.NewLine, lines);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String JoinLines(params String[] lines)
|
|
|
|
{
|
|
|
|
return String.Join(Environment.NewLine, lines);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String SeparatedBy(this IEnumerable<String> s, String separator)
|
|
|
|
{
|
|
|
|
return String.Join(separator, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Boolean IsInteger(this String s)
|
|
|
|
{
|
|
|
|
return Int64.TryParse(s, out var n);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-20 11:53:03 +00:00
|
|
|
public static String TrimStart(this String target, String trimString)
|
|
|
|
{
|
|
|
|
if (String.IsNullOrEmpty(trimString)) return target;
|
|
|
|
|
|
|
|
var result = target;
|
|
|
|
while (result.StartsWith(trimString))
|
|
|
|
result = result[trimString.Length..];
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String TrimEnd(this String target, String trimString)
|
|
|
|
{
|
|
|
|
if (String.IsNullOrEmpty(trimString))
|
|
|
|
return target;
|
|
|
|
|
|
|
|
var result = target;
|
|
|
|
while (result.EndsWith(trimString))
|
|
|
|
result = result[..^trimString.Length];
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String EnsureStartsWith(this String target, String prefix)
|
|
|
|
{
|
|
|
|
return $"{prefix}{target.TrimStart(prefix)}";
|
|
|
|
}
|
2023-02-16 12:57:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|