using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Quadarax.Foundation.Core.Value.Extensions
{
public static class StringExt
{
///
/// Default string comparer for like operator.
///
public static IEqualityComparer DefaultLikeComparer { get; set; } = new StringPatternComparer();
public static string Align(this string value, int size)
{
if (string.IsNullOrEmpty(value)) return new string(' ', size);
if (value.Length < size)
return value + new string(' ', size - value.Length);
return Truncate(value, size);
}
public static string Truncate(this string value, int maxLength)
{
if (string.IsNullOrEmpty(value)) return value;
return value.Length <= maxLength ? value : value.Substring(0, maxLength);
}
public static int SeparateValueCount(this string value, string separator)
{
var nSepLen = separator.Length;
var nStrLen = value.Length;
if (nStrLen == 0 || nSepLen == 0)
return nSepLen == 0 && nStrLen > 0 ? 1 : 0;
var nCnt = 0;
var nPos = value.IndexOf(separator, StringComparison.Ordinal);
while (nPos >= 0)
{
nCnt++;
nPos = value.IndexOf(separator, nPos + nSepLen, StringComparison.Ordinal);
}
return nCnt + 1;
}
public static string SeparateValue(this string value, string separator, int zeroBasedIndex)
{
var nSepLen = separator.Length;
var nStrLen = value.Length;
if (nStrLen == 0 || nSepLen == 0 || nSepLen > nStrLen)
throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
var nLastPos = 0;
var nPos = value.IndexOf(separator, StringComparison.Ordinal);
while (nPos >= 0)
{
if (zeroBasedIndex == 0)
break;
nLastPos = nPos + nSepLen;
nPos = value.IndexOf(separator, nPos + nSepLen, StringComparison.Ordinal);
zeroBasedIndex--;
}
if (zeroBasedIndex > 0)
throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
return value.Substring(nLastPos, nPos == -1 ? nStrLen - nLastPos : nPos - nLastPos);
}
public static string SeparateValueLast(this string value, string separator)
{
var nSepLen = separator.Length;
var nStrLen = value.Length;
if (nStrLen == 0 || nSepLen == 0 || nSepLen > nStrLen)
throw new IndexOutOfRangeException("SeparateValue method has index out of range.");
return value.SeparateValue(separator, value.SeparateValueCount(separator) - 1);
}
public static string RemoveLast(this string value)
{
return value.Length == 0 ? string.Empty : value.Substring(0, value.Length - 1);
}
public static string RemoveFirst(this string value)
{
return value.Length == 0 ? string.Empty : value.Substring(1, value.Length - 1);
}
public static int MaxLineChars(this string value)
{
var aParts = value.Split("/n");
return aParts.Length > 0 ? aParts.Max(x => x.Length) : value.Length;
}
public static string[] Split(this string value, string separator)
{
return value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
}
public static Tuple[] Extract(this string value, params string[] hashes) //hashtype, tashname
{
var oResult = new List>();
if (hashes.Length == 0)
return new Tuple[0];
var nLenIndex = value.Length + 1;
foreach (var sHash in hashes)
{
var bBeginBlock = true;
var nPos = value.IndexOf(sHash, StringComparison.InvariantCulture);
var nLenHash = sHash.Length;
if (nPos < 0)
continue;
while (nPos >= 0)
{
if (nPos + nLenHash > nLenIndex)
break;
var nEndPos = value.IndexOf(sHash, nPos + nLenHash, StringComparison.InvariantCulture);
if (nEndPos < 0)
break;
if (bBeginBlock)
{
var oEntry = new Tuple(sHash, value.Substring(nPos + nLenHash, nEndPos - nPos - nLenHash));
if (!oResult.Contains(oEntry))
oResult.Add(oEntry);
}
nPos = nEndPos;
bBeginBlock = !bBeginBlock;
}
}
return oResult.ToArray();
}
public static string EnsurePathBackslash(this string value)
{
if (string.IsNullOrEmpty(value))
return value;
value = value.Trim();
if (value.EndsWith(Path.DirectorySeparatorChar))
return value;
return value + Path.DirectorySeparatorChar;
}
public static string EnsurePathNonBackslash(this string value)
{
if (string.IsNullOrEmpty(value))
return value;
value = value.Trim();
if (!value.EndsWith(Path.DirectorySeparatorChar))
return value;
return value.RemoveLast();
}
public static string RemoveWhitespace(this string input)
{
return new string(input.ToCharArray()
.Where(c => !Char.IsWhiteSpace(c))
.ToArray());
}
///
/// Performs like operator on input string. customComparer can be provides to override default comparer.
///
/// Input string to compare
/// Search pattern corresponds with comparer implementation.
/// Custom comparer. If not set, use default comparer (defined in )
///
public static bool Like(this string input, string searchPattern, IEqualityComparer? customComparer = null)
{
customComparer ??= DefaultLikeComparer;
return customComparer.Equals(input, searchPattern);
}
///
/// Splits a string by the specified separator, but ignores separators that are within brackets/quotes.
///
/// The string to split
/// The separator string to split on
/// The opening bracket/quote character(s)
/// The closing bracket/quote character(s). If null, uses the same as beginBracket
/// If true, removes empty entries from the result
/// If true, trims whitespace from each result value
/// If true, keeps the begin and end brackets in the result
/// Array of split string parts
public static string[] SplitQuoted(this string value, string separator, string beginBracket, string? endBracket = null, bool removeEmptyItems = true, bool trimValues = true, bool keepBracket = false)
{
if (string.IsNullOrEmpty(value))
return new string[] { value ?? string.Empty };
if (string.IsNullOrEmpty(separator))
throw new ArgumentException("Separator cannot be null or empty", nameof(separator));
if (string.IsNullOrEmpty(beginBracket))
throw new ArgumentException("Begin bracket cannot be null or empty", nameof(beginBracket));
// If endBracket is not specified, use the same as beginBracket
endBracket ??= beginBracket;
var result = new List();
var currentPart = new StringBuilder();
var i = 0;
while (i < value.Length)
{
// Check if we're at the start of a separator
if (i <= value.Length - separator.Length &&
value.Substring(i, separator.Length) == separator)
{
// Found separator outside brackets, so add current part to result
result.Add(currentPart.ToString());
currentPart.Clear();
i += separator.Length;
continue;
}
// Check if we're at the start of a begin bracket
if (i <= value.Length - beginBracket.Length &&
value.Substring(i, beginBracket.Length) == beginBracket)
{
// Found begin bracket, add it to current part if keepBracket is true
if (keepBracket)
{
currentPart.Append(beginBracket);
}
i += beginBracket.Length;
// Now find the matching end bracket
var bracketDepth = 1;
while (i < value.Length && bracketDepth > 0)
{
// Check for end brackets first (important for single-character brackets like quotes)
if (i <= value.Length - endBracket.Length &&
value.Substring(i, endBracket.Length) == endBracket)
{
i += endBracket.Length;
bracketDepth--;
// Add the end bracket if we're still nested or if keepBracket is true for outermost
if (bracketDepth > 0 || keepBracket)
{
currentPart.Append(endBracket);
}
}
// Check for nested begin brackets (only if different from end bracket or if we haven't found end bracket)
else if (beginBracket != endBracket &&
i <= value.Length - beginBracket.Length &&
value.Substring(i, beginBracket.Length) == beginBracket)
{
currentPart.Append(beginBracket);
i += beginBracket.Length;
bracketDepth++;
}
else
{
// Regular character inside brackets
currentPart.Append(value[i]);
i++;
}
}
continue;
}
// Regular character outside brackets
currentPart.Append(value[i]);
i++;
}
// Add the last part
result.Add(currentPart.ToString());
// Process the result based on options
var finalResult = new List();
foreach (var part in result)
{
var processedPart = trimValues ? part.Trim() : part;
if (!removeEmptyItems || !string.IsNullOrEmpty(processedPart))
{
finalResult.Add(processedPart);
}
}
return finalResult.ToArray();
}
}
}