Files
Common-VS2019/SacsStandardBase/Base/Utils/StringUtil.cs
T

482 lines
17 KiB
C#

using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using System;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
namespace Sarand.Net.Standard.Base.Utils
{
//=======================================================================
public static class StringUtil
{
//-------------------------------------------------------------------
// U t i l i t i e s
//-------------------------------------------------------------------
public static String EmptyOnNull (String value)
{
return (value == null ? String.Empty : value);
}
public static String OnEmpty (String value, String defaultValue)
{
if (IsEmpty(value)) return defaultValue;
return value;
}
public static int GetLength (String value)
{
if (String.IsNullOrEmpty(value)) return 0;
return value.Length;
}
//-------------------------------------------------------------------
// C o m p a r i s o n
//-------------------------------------------------------------------
public static bool IsEmpty (this string value)
{
return String.IsNullOrEmpty(value);
}
public static bool EqualsCI (this String value1, String value2)
{
return String.Equals(value1, value2, StringComparison.OrdinalIgnoreCase);
}
public static bool StartsWithCI (this String value1, String value2)
{
if (IsEmpty(value1) || IsEmpty(value2)) return false;
return (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase));
}
public static bool EndsWithCI (this String value1, String value2)
{
if (IsEmpty(value1) || IsEmpty(value2)) return false;
return (value1.EndsWith(value2, StringComparison.OrdinalIgnoreCase));
}
public static bool ContainsCI (this String value1, String value2)
{
if (IsEmpty(value1) || IsEmpty(value2)) return false;
return (value1.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0);
}
//-------------------------------------------------------------------
// C o n t e n t
//-------------------------------------------------------------------
public static bool IsAlpha (this string value)
{
return EmptyOnNull(value).All(Char.IsLetter);
}
public static bool IsAlphaNumeric (this string value)
{
return EmptyOnNull(value).All(Char.IsLetterOrDigit);
}
public static bool IsNumeric (this string value, bool allowNegative = false)
{
Int64 number = 0;
if (!Int64.TryParse(value, out number)) return false;
return (allowNegative || number >= 0);
}
public static bool IsDecimal (this string value, bool allowNegative = false)
{
Decimal number = 0;
if (!Decimal.TryParse(value, out number)) return false;
return (allowNegative || number >= 0);
}
//-------------------------------------------------------------------
/// <summary>Test for Hex character.</summary>
public static bool IsHex (this char c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
/// <summary>Test for Hex string.</summary>
public static bool IsHex (this String value)
{
if (IsEmpty(value)) return false;
foreach (char c in value)
if (!IsHex(c)) return false;
return true;
}
//-------------------------------------------------------------------
// P a d d i n g
//-------------------------------------------------------------------
public static String PadLeft (this String value, int length, char pad = ' ')
{
value = StringUtil.EmptyOnNull(value);
while (value.Length < length)
value = pad + value;
return value;
}
public static String PadRight (this String value, int length, char pad = ' ')
{
value = StringUtil.EmptyOnNull(value);
while (value.Length < length)
value = value + pad;
return value;
}
//-------------------------------------------------------------------
// C o n v e r t
//-------------------------------------------------------------------
public static String CapitaliseFirst (this String value, TextInfo textInfo = null)
{
textInfo = (textInfo ?? CultureInfo.CurrentCulture.TextInfo);
if (StringUtil.IsEmpty(value)) return value;
return textInfo.ToUpper(value.First()) + value.Substring(1);
}
public static string ToTitleCase (this string value, TextInfo textInfo = null)
{
textInfo = (textInfo ?? CultureInfo.CurrentCulture.TextInfo);
String[] tokens = value.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < tokens.Length; i++)
{
String token = tokens[i];
tokens[i] = textInfo.ToUpper(token.First()) + token.Substring(1);
}
return string.Join(" ", tokens);
}
//-------------------------------------------------------------------
// C l e a n s e
//-------------------------------------------------------------------
/// <summary>Trim leading, trailling and multiple internal spaces.</summary>
public static String TrimAll (this String value)
{
if (IsEmpty(value)) return value;
value = value.Trim().TrimInternalSpaces();
return value;
}
/// <summary>
/// Trim any combination of the specified characters from the start,
/// end and where more than one found together internally,
/// replacing with the specified string.
/// </summary>
/// <param name="value"></param>
/// <param name="trimCharacters"></param>
/// <returns></returns>
public static String TrimAll (this String value, char[] trimChars, String replacement = " ")
{
if (IsEmpty(value) || trimChars.Length < 1) return value;
// Trim leading and trailing.
value = value.Trim(trimChars);
// Use regex to replace multiple internal.
Regex regexMultipleInternal = new Regex("["+Regex.Escape(new String(trimChars))+"]{2,}", RegexOptions.None);
return regexMultipleInternal.Replace(value, replacement);
}
private static Regex regexMultipleSpaces = new Regex("[ ]{2,}", RegexOptions.Compiled);
public static String TrimInternalSpaces (this String value)
{
return regexMultipleSpaces.Replace(value, " ");
}
//-------------------------------------------------------------------
// R e p l a c e
//-------------------------------------------------------------------
/// <summary>Replace any of the characters in the search string with the specified replacement character.</summary>
public static string ReplaceAny (this string value, String searchChars, char replaceChar)
{
for (int i = 0; i < searchChars.Length; i++)
value = value.Replace(searchChars[i], replaceChar);
return value;
}
/// <summary>
/// Replace all occurences of any of the search strings with the replace string, even where search values remain after the each replacement.
/// <para>NB Use String.Replace if the replacement contains the search string</para>
/// </summary>
public static string ReplaceAll (this string value, String search, String replace)
{
return value.ReplaceAll(new String[] { search }, replace);
}
public static string ReplaceAll (this string value, String[] searches, String replace)
{
foreach (String search in searches)
{
while (value.Contains(search))
{
value = value.Replace(search, replace);
if (value.Contains(search) && replace.Contains(search))
throw new NotSupportedException("StringUtil.ReplaceAll Replace value cannot contain search value");
}
}
return value;
}
/// <summary>Duplicate every instance of the specified character.</summary>
public static String Duplicate (this String value, char search)
{
return value.Replace(search.ToString(), search.ToString() + search.ToString());
}
//-------------------------------------------------------------------
// E x t r a c t i o n
//-------------------------------------------------------------------
public static string Left (this string value, int length)
{
if (String.IsNullOrEmpty(value)) return value;
if (length < 0) return String.Empty;
return (length >= value.Length ? value : value.Substring(0, length));
}
public static string Right (this string value, int length)
{
if (String.IsNullOrEmpty(value)) return value;
if (length < 0) return String.Empty;
return
(
length >= value.Length
? value
: value.Substring(value.Length - length)
);
}
/// <summary>
/// <para>Safe SubString - avoinding out of bounds exceptions etc.</para>
/// </summary>
/// <param name="value"></param>
/// <param name="start"></param>
/// <param name="length"></param>
/// <returns></returns>
public static string SubstringSafe (this string value, int start, int length = -1)
{
if (String.IsNullOrEmpty(value)) return String.Empty;
start = Math.Max(0, start);
if (start >= value.Length) return String.Empty;
value = value.Substring(start);
if (length < 0 || length > value.Length) return value;
return value.Substring(0, length);
}
//-------------------------------------------------------------------
// C o n v e r s i o n
//-------------------------------------------------------------------
// Integer values.
public static short ToShort (this string value, short defaultValue = 0)
{
return (short)ToLong(value, defaultValue);
}
public static int ToInt (this string value, int defaultValue = 0)
{
return (int)ToLong(value, defaultValue);
}
public static long ToLong (this string value, long defaultValue = 0)
{
if (String.IsNullOrEmpty(value)) return defaultValue;
try
{
Double returnValue = defaultValue;
if (Double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out returnValue))
return (Int64)returnValue;
}
catch (Exception) { }
return defaultValue;
}
public static short ToShort (Object value, short defaultValue = 0)
{
return (short)ToLong(value, defaultValue);
}
public static int ToInt (Object value, int defaultValue = 0)
{
return (int)ToLong(value, defaultValue);
}
public static long ToLong (Object value, long defaultValue = 0)
{
if (value == null) return defaultValue;
try
{
return ToLong(value.ToString());
}
catch (Exception) { }
return defaultValue;
}
//---------------------------------------------------------------------------
// SysId.
public static SysId ToSysId(this String value)
{
return new SysId(StringUtil.ToLong(value));
}
//---------------------------------------------------------------------------
// Hex values to integer.
/// <summary>Convert hex character to integer value.</summary>
public static byte ToHex (this char value)
{
if (value >= '0' && value <= '9') return (byte)(value - '0');
if (value >= 'A' && value <= 'F') return (byte)(value - 'A' + 10);
if (value >= 'a' && value <= 'f') return (byte)(value - 'a' + 10);
return 0;
}
/// <summary>Convert pair of hex character to integer value.</summary>
public static byte ToHex (char cHex1, char cHex2)
{
return (byte)((ToHex(cHex1) * 16) + ToHex(cHex2));
}
/// <summary>Convert hex strings to integer value.</summary>
public static ulong ToHex (this String value)
{
if (IsEmpty(value)) return 0;
ulong intValue = 0;
foreach (char c in value)
{
// Shift previous value half a byte (nibble) - equivalent to single hex character.
intValue <<= 4;
// Get value of next hex character.
byte charValue = ToHex (c);
intValue += charValue;
}
return intValue;
}
//-------------------------------------------------------------------
// Floating point values.
public static float ToSingle (this string value, float defaultValue = 0)
{
return Convert.ToSingle(ToDouble(value, defaultValue));
}
public static double ToDouble (this string value, double defaultValue = 0)
{
if (String.IsNullOrEmpty(value)) return defaultValue;
try
{
Double returnValue = defaultValue;
if (Double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out returnValue))
return returnValue;
}
catch (Exception) { }
return defaultValue;
}
public static float ToSingle (Object value, float defaultValue = 0)
{
return Convert.ToSingle(ToDouble(value, defaultValue));
}
public static double ToDouble (Object value, double defaultValue = 0)
{
if (value == null) return defaultValue;
try
{
return ToDouble(value.ToString());
}
catch (Exception) { }
return defaultValue;
}
//-------------------------------------------------------------------
// Decimal values.
public static decimal ToDecimal (this string value, decimal defaultValue = 0)
{
if (String.IsNullOrEmpty(value)) return defaultValue;
try
{
Decimal returnValue = defaultValue;
if (Decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out returnValue))
return returnValue;
}
catch (Exception) { }
return defaultValue;
}
public static decimal ToDecimal (Object value, decimal defaultValue = 0)
{
if (value == null) return defaultValue;
try
{
return ToDecimal(value.ToString());
}
catch (Exception) { }
return defaultValue;
}
//-------------------------------------------------------------------
// Boolean values.
public static bool ToBool (this string value)
{
return value.IsTrue();
}
public static bool IsTrue (this string value)
{
if (String.IsNullOrEmpty(value)) return false;
if (value.ToLong() != 0) return true;
if (value.ToDouble() != 0.0) return true;
if (value.Left(1).EqualsCI("Y")) return true;
if (value.EqualsCI("True")) return true;
return false;
}
//-------------------------------------------------------------------
// F o r m a t t i n g
//-------------------------------------------------------------------
public static String FormatNumeric (double numericValue, ushort decimalPlaces = 0, ushort sigFigs = 0, char thousandsDelim = '\0', char decimalDelim = '.')
{
String value = String.Empty;
try
{
String format = "F"+decimalPlaces.ToString();
if (thousandsDelim != '\0')
format = "N" + decimalPlaces.ToString();
value = numericValue.ToString(format);
}
catch (Exception exc)
{
SaLogger.Debug("StringUtil.FormatNumeric(double) " + exc.GetType().Name + ": " + exc.Message);
}
return value;
}
public static String FormatNumeric (decimal numericValue, ushort decimalPlaces = 0, ushort sigFigs = 0, char thousandsDelim = '\0', char decimalDelim = '.')
{
String value = String.Empty;
try
{
String format = "F"+decimalPlaces.ToString();
if (thousandsDelim != '\0')
format = "N" + decimalPlaces.ToString();
value = numericValue.ToString(format);
}
catch (Exception exc)
{
SaLogger.Debug("StringUtil.FormatNumeric(decimal) " + exc.GetType().Name + ": " + exc.Message);
}
return value;
}
//-------------------------------------------------------------------
// Specialist finding.
public static int FindMatchingBrace (this String value, int braceOpenPos)
{
if (String.IsNullOrEmpty(value) || braceOpenPos < 0 || braceOpenPos >= value.Length) return -1;
char sourceBrace = value[braceOpenPos];
char targetBrace = '\0'; // Target character to be found.
bool openBraceFound = false; // Identifies forward or backwards search (close or open bracket to be found).
// Identify the target bracket character:
switch (sourceBrace)
{
case '(': targetBrace = ')'; openBraceFound = true; break;
case ')': targetBrace = '('; break;
case '[': targetBrace = ']'; openBraceFound = true; break;
case ']': targetBrace = '['; break;
case '{': targetBrace = '}'; openBraceFound = true; break;
case '}': targetBrace = '{'; break;
case '<': targetBrace = '>'; openBraceFound = true; break;
case '>': targetBrace = '<'; break;
}
// Verify that a valid bracket has been found:
if (targetBrace == 0) return -1;
// Start search from the 'source' bracket position:
int braceCount = 1; // Search continues until this count gets back down to '0'.
int searchPos = braceOpenPos;
while (true)
{
// Navigate to next character to be checked (direction depends on whether target is open or close bracket):
if (openBraceFound) searchPos++; else searchPos--;
if (searchPos < 0 || searchPos >= value.Length) return -1;
// If character at this position is the 'source' bracket, increment count (another level of embedded brackets):
char searchChar = value[searchPos];
if (searchChar == sourceBrace) braceCount++;
else if (searchChar == targetBrace)
{
braceCount--;
if (braceCount == 0) return searchPos; // Matching bracket found.
else if (braceCount < 0) return -1; // Invalid combination of brackets.
}
}
//return -1; Unreachable code!
}
//-------------------------------------------------------------------
}
//=======================================================================
}