using System; using System.Collections.Generic; using System.Globalization; namespace PKHeX.Core; /// /// Utility for searching strings within arrays or within another string. /// public static class StringUtil { private static readonly CompareInfo CompareInfo = CultureInfo.CurrentCulture.CompareInfo; /// /// Finds the index of the string within the array by ignoring casing, spaces, and punctuation. /// /// Array of strings to search in /// Value to search for /// Index within public static int FindIndexIgnoreCase(string[] arr, string value) => Array.FindIndex(arr, z => IsMatchIgnoreCase(z, value)); /// /// Gets the indexes by calling for all . /// /// Array of strings to search in /// Items to search for /// Index within public static int[] GetIndexes(string[] arr, IReadOnlyList items) => GetIndexes(arr, items, 0, items.Count); /// /// Gets the indexes by calling for all . /// /// Array of strings to search in /// Items to search for /// Starting index within /// Amount to convert within /// Index within public static int[] GetIndexes(string[] arr, IReadOnlyList items, int start, int length) { if (length < 0) length = items.Count - start; var result = new int[length]; for (int i = 0; i < result.Length; i++) result[i] = FindIndexIgnoreCase(arr, items[start + i]); return result; } public static bool IsMatchIgnoreCase(string string1, string string2) { if (string1.Length != string2.Length) return false; const CompareOptions options = CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreWidth; var compare = CompareInfo.Compare(string1, string2, options); return compare == 0; } /// /// Gets the string entry within the input , based on the and position. /// public static string GetNthEntry(ReadOnlySpan line, int nth, int start, char separator = ',') { if (nth != 1) start = line.IndexOfNth(separator, nth - 1, start + 1); var end = line.IndexOfNth(separator, 1, start + 1); if (end == -1) return new string(line[(start + 1)..].ToArray()); return new string(line[(start + 1)..end].ToArray()); } private static int IndexOfNth(this ReadOnlySpan s, char t, int n, int start) { int count = 0; for (int i = start; i < s.Length; i++) { if (s[i] != t) continue; if (++count == n) return i; } return -1; } /// /// Converts an all-caps hex string to a byte array. /// public static byte[] ToByteArray(this string toTransform) { var result = new byte[toTransform.Length / 2]; for (int i = 0; i < result.Length; i++) { var ofs = i << 1; var _0 = toTransform[ofs + 0]; var _1 = toTransform[ofs + 1]; result[i] = DecodeTuple(_0, _1); } return result; } private static bool IsNum(char c) => (uint)(c - '0') <= 9; private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5; private static byte DecodeTuple(char _0, char _1) { byte result; if (IsNum(_0)) result = (byte)((_0 - '0') << 4); else if (IsHexUpper(_0)) result = (byte)((_0 - 'A' + 10) << 4); else throw new ArgumentOutOfRangeException(nameof(_0)); if (IsNum(_1)) result |= (byte)(_1 - '0'); else if (IsHexUpper(_1)) result |= (byte)(_1 - 'A' + 10); else throw new ArgumentOutOfRangeException(nameof(_1)); return result; } }