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() ?? ""; } 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 strings) { return String.Join("", strings); } public static String JoinWith(this IEnumerable strings, String separator) { 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) { return Enumerable .Repeat(indent, text.SplitLines().Count) .JoinLines() .SideBySideWith(text, ""); } public static IReadOnlyList 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(this IEnumerable args, String separator) { return String.Join(separator, args); } public static IEnumerable GetLinesStartingWith(this IEnumerable lines, String prefix) { return lines.Where(l => l.StartsWith(prefix)); } public static String GetLineStartingWith(this IEnumerable 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 lines) { return String.Join(Environment.NewLine, lines.Unless(String.IsNullOrWhiteSpace)); } public static String JoinLines(this IEnumerable 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 s, String separator) { return String.Join(separator, s); } public static Boolean IsInteger(this String s) { return Int64.TryParse(s, out var n); } 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)}"; } }