/// <summary> /// 随机打乱字符串中的所有字符 /// </summary> /// <param name="str">需要被打乱的字符串</param> /// <param name="seed">种子</param> /// <returns>被打乱的字符串</returns> public static string Shuffle(string str, int?seed = null) { KGuard.Requires <ArgumentNullException>(str != null); var random = KUtil.MakeRandom(seed); var requested = new string[str.Length]; for (var i = 0; i < str.Length; i++) { var index = random.Next(0, str.Length - 1); requested[i] = requested[i] ?? str.Substring(i, 1); requested[index] = requested[index] ?? str.Substring(index, 1); if (index == i) { continue; } var temp = requested[i]; requested[i] = requested[index]; requested[index] = temp; } return(KArray.Reduce(requested, (v1, v2) => v1 + v2, string.Empty)); }
/// <summary> /// 将一个或多个元素加入数组尾端 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="elements">要加入的元素</param> /// <returns>数组的元素个数</returns> public static int Push <T>(ref T[] source, params T[] elements) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <InvalidOperationException>(elements != null); Array.Resize(ref source, source.Length + elements.Length); Array.Copy(elements, 0, source, source.Length - elements.Length, elements.Length); return(source.Length); }
/// <summary> /// 删除数组中的最后一个元素,并将删除的元素作为返回值返回 /// </summary> /// <typeparam name="T">删除数组中的最后一个元素</typeparam> /// <param name="source">规定数组</param> /// <returns>被删除的元素</returns> public static T Pop <T>(ref T[] source) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <InvalidOperationException>(source.Length > 0); T result = source[source.Length - 1]; Array.Resize(ref source, source.Length - 1); return(result); }
/// <summary> /// 替换规定字符串中从后往前第一次遇到的匹配项 /// <para>该函数对大小写敏感</para> /// </summary> /// <param name="match">匹配项</param> /// <param name="replace">替换的内容</param> /// <param name="str">规定字符串</param> /// <returns>替换后的字符串</returns> public static string ReplaceLast(string match, string replace, string str) { KGuard.Requires <ArgumentNullException>(match != null); KGuard.Requires <ArgumentNullException>(replace != null); KGuard.Requires <ArgumentNullException>(str != null); var index = str.LastIndexOf(match, StringComparison.Ordinal); return(index < 0 ? str : str.Remove(index, match.Length).Insert(index, replace)); }
/// <summary> /// 在数组中根据条件取出一段值,并返回。 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="start"> /// 取出元素的开始位置。 /// <para>如果该值设置为正数,则从前往后开始取</para> /// <para>如果该值设置为负数,则从后向前取 <paramref name="start"/> 绝对值。-2 意味着从数组的倒数第二个元素开始</para> /// </param> /// <param name="length"> /// 被返回数组的长度 /// <para>如果该值设置为整数,则返回该数量的元素。</para> /// <para>如果该值设置为负数,则则从后向前取 <paramref name="length"/> 绝对值位置终止取出。-1 意味着从数组的倒数第一个元素前终止</para> /// <para>如果该值未设置,则返回从 <paramref name="start"/> 参数设置的位置开始直到数组末端的所有元素。</para> /// </param> /// <returns>取出的数组</returns> public static T[] Slice <T>(T[] source, int start, int?length = null) { KGuard.Requires <ArgumentNullException>(source != null); KUtil.NormalizationPosition(source.Length, ref start, ref length); var requested = new T[length.Value]; Array.Copy(source, start, requested, 0, length.Value); return(requested); }
/// <summary> /// 在规定字符串中替换匹配项 /// </summary> /// <param name="matches">匹配项</param> /// <param name="replace">替换的值</param> /// <param name="str">规定字符串</param> /// <returns></returns> public static string Replace(string[] matches, string replace, string str) { KGuard.Requires <ArgumentNullException>(matches != null); KGuard.Requires <ArgumentNullException>(replace != null); KGuard.Requires <ArgumentNullException>(str != null); foreach (var match in matches) { str = str.Replace(match, replace); } return(str); }
/// <summary> /// 删除数组中第一个元素,并返回被删除元素的值 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <returns>被删除元素的值</returns> public static T Shift <T>(ref T[] source) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <InvalidOperationException>(source.Length > 0); var requested = source[0]; var newSource = new T[source.Length - 1]; Array.Copy(source, 1, newSource, 0, source.Length - 1); source = newSource; return(requested); }
/// <summary> /// 向用户自定义函数发送数组中的值,并返回一个字符串 /// <para>如果数组是空的且未传递<paramref name="initial"/>参数,该函数返回 null</para> /// <para>如果指定了<paramref name="initial"/>参数,则该参数将被当成是数组中的第一个值来处理,如果数组为空的话就作为最终返回值(string)</para> /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="callback">自定义函数</param> /// <param name="initial">初始值</param> /// <returns></returns> public static string Reduce <T>(T[] source, Func <object, T, string> callback, object initial = null) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <ArgumentNullException>(callback != null); var requested = initial; foreach (var segments in source) { requested = callback.Invoke(requested, segments); } return(requested == null ? null : requested.ToString()); }
/// <summary> /// 根据长度将字符串分割到数组中 /// </summary> /// <param name="str">要分割的字符串</param> /// <param name="length">规定每个数组元素的长度。默认是 1。</param> /// <returns>分割的字符串</returns> public static string[] Split(string str, int length = 1) { KGuard.Requires <ArgumentNullException>(str != null); KGuard.Requires <ArgumentOutOfRangeException>(length > 0); var requested = new string[str.Length / length + (str.Length % length == 0 ? 0 : 1)]; for (var i = 0; i < str.Length; i += length) { requested[i / length] = str.Substring(i, Math.Min(str.Length - i, length)); } return(requested); }
/// <summary> /// 向数组插入新元素。新数组的值将被插入到数组的开头。 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="elements">插入的元素</param> /// <returns>数组元素个数</returns> public static int Unshift <T>(ref T[] source, params T[] elements) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <ArgumentNullException>(elements != null); var newSource = new T[source.Length + elements.Length]; Array.Copy(elements, newSource, elements.Length); Array.Copy(source, 0, newSource, elements.Length, source.Length); source = newSource; return(source.Length); }
/// <summary> /// 判断规定字符串是否包含规定子字符串 /// <para>子字符串是识别大小写的</para> /// <para></para> /// </summary> /// <param name="str">规定字符串</param> /// <param name="needles">规定子字符串</param> /// <returns>是否包含</returns> public static bool Contains(string str, params string[] needles) { KGuard.Requires <ArgumentNullException>(str != null); KGuard.Requires <ArgumentNullException>(needles != null); foreach (var needle in needles) { if (str.Contains(needle)) { return(true); } } return(false); }
/// <summary> /// 将数组值传入用户自定义函数,自定义函数返回的值作为新的数组值 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="callback">自定义函数</param> /// <returns>处理后的数组</returns> public static T[] Map <T>(T[] source, Func <T, T> callback) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <ArgumentNullException>(callback != null); var requested = new T[source.Length]; Array.Copy(source, requested, source.Length); for (var i = 0; i < source.Length; i++) { requested[i] = callback.Invoke(source[i]); } return(requested); }
/// <summary> /// 在规定字符串中查找在规定搜索值,并在规定搜索值之后返回规定字符串的剩余部分。 /// <para>如果没有找到则返回规定字符串本身</para> /// </summary> /// <param name="str">规定字符串</param> /// <param name="search">规定搜索值</param> /// <returns>剩余部分</returns> public static string After(string str, string search) { KGuard.Requires <ArgumentNullException>(search != null); if (str == null || str.Length <= 0) { return(str); } var index = str.IndexOf(search); if (index < 0) { return(str); } return(str.Substring(index + search.Length, str.Length - index - search.Length)); }
/// <summary> /// 从数组中移除指定长度的元素,如果给定了<paramref name="replSource"/>参数,那么新元素从<paramref name="start"/>位置开始插入 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="start"> /// 删除元素的开始位置。 /// <para>如果该值设置为正数,则从前往后开始删除</para> /// <para>如果该值设置为负数,则从后向前取 <paramref name="start"/> 绝对值。-2 意味着从数组的倒数第二个元素开始</para></param> /// <param name="length"> /// 删除元素的个数,也是被返回数组的长度 /// <para>如果该值设置为整数,则返回该数量的元素。</para> /// <para>如果该值设置为负数,则则从后向前取 <paramref name="length"/> 绝对值位置终止删除。-1 意味着从数组的倒数第一个元素前删除</para> /// <para>如果该值未设置,则返回从 <paramref name="start"/> 参数设置的位置开始直到数组末端的所有元素。</para> /// </param> /// <param name="replSource">在start位置插入的数组</param> /// <returns>被删除的数组</returns> public static T[] Splice <T>(ref T[] source, int start, int?length = null, T[] replSource = null) { KGuard.Requires <ArgumentNullException>(source != null); KUtil.NormalizationPosition(source.Length, ref start, ref length); var requested = new T[length.Value]; if (length.Value == source.Length) { // 现在移除所有旧的元素,然后用新的元素替换。 Array.Copy(source, requested, source.Length); source = replSource ?? new T[] { }; return(requested); } Array.Copy(source, start, requested, 0, length.Value); if (replSource == null || replSource.Length == 0) { var newSource = new T[source.Length - length.Value]; // 现在只删除不插入 if (start > 0) { Array.Copy(source, 0, newSource, 0, start); } Array.Copy(source, start + length.Value, newSource, start, source.Length - (start + length.Value)); source = newSource; } else { var newSource = new T[source.Length - length.Value + replSource.Length]; // 删除并且插入 if (start > 0) { Array.Copy(source, 0, newSource, 0, start); } Array.Copy(replSource, 0, newSource, start, replSource.Length); Array.Copy(source, start + length.Value, newSource, start + replSource.Length, source.Length - (start + length.Value)); source = newSource; } return(requested); }
/// <summary> /// 将字符串重复指定的次数 /// </summary> /// <param name="str">需要被重复的字符串</param> /// <param name="num">重复的次数</param> /// <returns>重复后的字符串</returns> public static string Repeat(string str, int num) { KGuard.Requires <ArgumentNullException>(str != null); KGuard.Requires <ArgumentOutOfRangeException>(num >= 0); if (num == 0) { return(str); } var requested = new StringBuilder(); for (var i = 0; i < num; i++) { requested.Append(str); } return(requested.ToString()); }
/// <summary> /// 从规定数组中获取一个或者指定数量的随机值 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="number">随机的数量</param> /// <returns>随机后的元素</returns> public static T[] Rand <T>(T[] source, int number = 1) { KGuard.Requires <ArgumentNullException>(source != null); number = Math.Max(number, 1); source = Shuffle(source); var requested = new T[number]; var i = 0; foreach (var result in source) { if (i >= number) { break; } requested[i++] = result; } return(requested); }
/// <summary> /// 生成一个随机字母(含大小写),数字的字符串。 /// </summary> /// <param name="length">字符串长度</param> /// <param name="seed">种子</param> /// <returns>随机的字符串</returns> public static string Random(int length = 16, int?seed = null) { KGuard.Requires <ArgumentOutOfRangeException>(length > 0); var requested = string.Empty; var random = KUtil.MakeRandom(seed); for (int len; (len = requested.Length) < length;) { var size = length - len; var bytes = new byte[size]; random.NextBytes(bytes); var code = Replace(new[] { "/", "+", "=" }, string.Empty, Convert.ToBase64String(bytes)); requested += code.Substring(0, Math.Min(size, code.Length)); } return(requested); }
/// <summary> /// 输入数组中的每个值传给回调函数,如果回调函数返回 true,则把输入数组中的当前值加入结果数组中 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="predicate">回调函数</param> /// <returns>需求数组</returns> public static T[] Filter <T>(T[] source, Predicate <T> predicate) { KGuard.Requires <ArgumentNullException>(source != null); KGuard.Requires <ArgumentNullException>(predicate != null); var elements = new T[source.Length]; var i = 0; foreach (var result in source) { if (predicate.Invoke(result)) { elements[i++] = result; } } Array.Resize(ref elements, i); return(elements); }
/// <summary> /// 将多个规定数组合并成一个数组 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="sources">规定数组</param> /// <returns>合并后的数组</returns> public static T[] Merge <T>(params T[][] sources) { KGuard.Requires <ArgumentNullException>(sources != null); var length = 0; foreach (var source in sources) { length += source.Length; } var merge = new T[length]; var current = 0; foreach (var source in sources) { Array.Copy(source, 0, merge, current, source.Length); current += source.Length; } return(merge); }
/// <summary> /// 计算子串在字符串中出现的次数 /// <para>该函数不计数重叠的子串</para> /// </summary> /// <param name="str">规定字符串</param> /// <param name="subStr">子字符串</param> /// <param name="start">起始位置</param> /// <param name="length">需要扫描的长度</param> /// <param name="comparison">扫描规则</param> /// <returns>子字符串出现的次数</returns> public static int SubstringCount(string str, string subStr, int start = 0, int?length = null, StringComparison comparison = StringComparison.CurrentCultureIgnoreCase) { KGuard.Requires <ArgumentNullException>(str != null); KGuard.Requires <ArgumentNullException>(subStr != null); KUtil.NormalizationPosition(str.Length, ref start, ref length); var count = 0; while (length.Value > 0) { int index; if ((index = str.IndexOf(subStr, start, length.Value, comparison)) < 0) { break; } count++; length -= index + subStr.Length - start; start = index + subStr.Length; } return(count); }
/// <summary> /// 将规定数组中的元素打乱 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="seed">种子</param> /// <returns>打乱后的数组</returns> public static T[] Shuffle <T>(T[] source, int?seed = null) { KGuard.Requires <ArgumentNullException>(source != null); var requested = new T[source.Length]; Array.Copy(source, requested, source.Length); var random = KUtil.MakeRandom(seed); for (var i = 0; i < requested.Length; i++) { var index = random.Next(0, requested.Length - 1); if (index == i) { continue; } var temp = requested[i]; requested[i] = requested[index]; requested[index] = temp; } return(requested); }
/// <summary> /// 把字符串填充为新的长度。 /// </summary> /// <param name="str">规定要填充的字符串</param> /// <param name="length">规定新的字符串长度。如果该值小于字符串的原始长度,则不进行任何操作。</param> /// <param name="padStr"> /// 规定供填充使用的字符串。默认是空白。 /// <para>如果传入的字符串长度小于等于0那么会使用空白代替。</para> /// <para>注释:空白不是空字符串</para> /// </param> /// <param name="type"> /// 规定填充字符串的哪边。 /// <para><see cref="PadTypes.Both"/>填充字符串的两侧。如果不是偶数,则右侧获得额外的填充。</para> /// <para><see cref="PadTypes.Left"/>填充字符串的左侧。</para> /// <para><see cref="PadTypes.Right"/>填充字符串的右侧。默认。</para> /// </param> /// <returns>被填充的字符串</returns> public static string Pad(string str, int length, string padStr = null, PadTypes type = PadTypes.Right) { KGuard.Requires <ArgumentNullException>(str != null); var needPadding = length - str.Length; if (needPadding <= 0) { return(str); } int rightPadding; var leftPadding = rightPadding = 0; if (type == PadTypes.Both) { leftPadding = needPadding >> 1; rightPadding = (needPadding >> 1) + (needPadding % 2 == 0 ? 0 : 1); } else if (type == PadTypes.Right) { rightPadding = needPadding; } else { leftPadding = needPadding; } padStr = padStr ?? " "; padStr = padStr.Length <= 0 ? " " : padStr; var leftPadCount = leftPadding / padStr.Length + (leftPadding % padStr.Length == 0 ? 0 : 1); var rightPadCount = rightPadding / padStr.Length + (rightPadding % padStr.Length == 0 ? 0 : 1); return(Repeat(padStr, leftPadCount).Substring(0, leftPadding) + str + Repeat(padStr, rightPadCount).Substring(0, rightPadding)); }
/// <summary> /// 对数组进行填充,如果传入了规定数组,那么会在规定数组的基础上进行填充 /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="start">起始下标</param> /// <param name="length">填充长度</param> /// <param name="value">填充的值</param> /// <param name="source">规定数组</param> /// <returns>填充后的数组</returns> public static T[] Fill <T>(int start, int length, T value, T[] source = null) { KGuard.Requires <ArgumentOutOfRangeException>(start >= 0); KGuard.Requires <ArgumentOutOfRangeException>(length > 0); var count = start + length; var requested = new T[source == null ? count : source.Length + count]; if (start > 0 && source != null) { Array.Copy(source, requested, Math.Min(source.Length, start)); } for (var i = start; i < count; i++) { requested[i] = value; } if (source != null && start < source.Length) { Array.Copy(source, start, requested, count, source.Length - start); } return(requested); }
/// <summary> /// 将数组分为新的数组块 /// <para>其中每个数组的单元数目由 <paramref name="size"/> 参数决定。最后一个数组的单元数目可能会少几个。</para> /// </summary> /// <typeparam name="T">数组类型</typeparam> /// <param name="source">规定数组</param> /// <param name="size">每个分块的大小</param> /// <returns></returns> public static T[][] Chunk <T>(T[] source, int size) { KGuard.Requires <ArgumentNullException>(source != null); size = Math.Max(1, size); var requested = new T[source.Length / size + (source.Length % size == 0 ? 0 : 1)][]; T[] chunk = null; for (var i = 0; i < source.Length; i++) { var pos = i / size; if (i % size == 0) { if (chunk != null) { requested[pos - 1] = chunk; } chunk = new T[(i + size) <= source.Length ? size : source.Length - i]; } chunk[i - (pos * size)] = source[i]; } requested[requested.Length - 1] = chunk; return(requested); }