将string分成长度可变的较小的string
我想通过一定的长度variables来分割一个string。
当string的最后一段长度不能长于或长于长度时,它需要进行边界检查以防止爆炸。 寻找最简洁(但可以理解)的版本。
例:
string x = "AAABBBCC"; string[] arr = x.SplitByLength(3); // arr[0] -> "AAA"; // arr[1] -> "BBB"; // arr[2] -> "CC"
你需要使用一个循环:
public static IEnumerable<string> SplitByLength(this string str, int maxLength) { for (int index = 0; index < str.Length; index += maxLength) { yield return str.Substring(index, Math.Min(maxLength, str.Length - index)); } }
替代scheme:
public static IEnumerable<string> SplitByLength(this string str, int maxLength) { int index = 0; while(true) { if (index + maxLength >= str.Length) { yield return str.Substring(index); yield break; } yield return str.Substring(index, maxLength); index += maxLength; } }
第二种替代方法:(对于那些不能忍受while(true)
)
public static IEnumerable<string> SplitByLength(this string str, int maxLength) { int index = 0; while(index + maxLength < str.Length) { yield return str.Substring(index, maxLength); index += maxLength; } yield return str.Substring(index); }
易于理解的版本:
string x = "AAABBBCC"; List<string> a = new List<string>(); for (int i = 0; i < x.Length; i += 3) { if((i + 3) < x.Length) a.Add(x.Substring(i, 3)); else a.Add(x.Substring(i)); }
虽然最好3应该是一个不错的常量。
这不是特别简洁,但我可以使用这样的扩展方法:
public static IEnumerable<string> SplitByLength(this string s, int length) { for (int i = 0; i < s.Length; i += length) { if (i + length <= s.Length) { yield return s.Substring(i, length); } else { yield return s.Substring(i); } } }
请注意,我返回一个IEnumerable<string>
,而不是一个数组。 如果要将结果转换为数组,请使用ToArray
:
string[] arr = x.SplitByLength(3).ToArray();
这是我会做的:
public static IEnumerable<string> EnumerateByLength(this string text, int length) { int index = 0; while (index < text.Length) { int charCount = Math.Min(length, text.Length - index); yield return text.Substring(index, charCount); index += length; } }
这个方法会提供延迟执行(这对于像string
这样的不可变类来说并不重要,但是值得注意)。
那么如果你想要一个方法来为你填充一个数组,你可以有:
public static string[] SplitByLength(this string text, int length) { return text.EnumerateByLength(length).ToArray(); }
我之所以使用名称EnumerateByLength
而不是SplitByLength
作为“core”方法,是因为string.Split
返回一个string[]
,所以在我看来,名称以Split
开头的方法返回数组的优先顺序。
虽然这只是我。
我的解决scheme
public static string[] SplitToChunks(this string source, int maxLength) { return source .Where((x, i) => i % maxLength == 0) .Select( (x, i) => new string(source .Skip(i * maxLength) .Take(maxLength) .ToArray())) .ToArray(); }
我实际上宁愿使用List<string>
而不是string[]
。
在.NET 4.0上使用MoreLinq
Batch
:
public static IEnumerable<string> SplitByLength(this string str, int length) { return str.Batch(length, String.Concat); }
在3.5 Concat需要一个数组,所以我们可以使用Concat
和ToArray
或者new String
:
public static IEnumerable<string> SplitByLength(this string str, int length) { return str.Batch(length, chars => new String(chars.ToArray())); }
将string看作字符集合可能有点不直观,因此可能会提供string操作。
又一个轻微的变体(经典而简单实用):
class Program { static void Main(string[] args) { string msg = "AAABBBCC"; string[] test = msg.SplitByLength(3); } } public static class SplitStringByLength { public static string[] SplitByLength(this string inputString, int segmentSize) { List<string> segments = new List<string>(); int wholeSegmentCount = inputString.Length / segmentSize; int i; for (i = 0; i < wholeSegmentCount; i++) { segments.Add(inputString.Substring(i * segmentSize, segmentSize)); } if (inputString.Length % segmentSize != 0) { segments.Add(inputString.Substring(i * segmentSize, inputString.Length - i * segmentSize)); } return segments.ToArray(); } }
UPD:使用一些Linq使其实际上简洁
static IEnumerable EnumerateByLength(string str, int len) { Match m = (new Regex(string.Format("^(.{{1,{0}}})*$", len))).Match(str); if (m.Groups.Count <= 1) return Empty; return (from Capture c in m.Groups[1].Captures select c.Value); }
初始版本:
static string[] Empty = new string [] {}; static string[] SplitByLength(string str, int len) { Regex r = new Regex(string.Format("^(.{{1,{0}}})*$",len)); Match m = r.Match(str); if(m.Groups.Count <= 1) return Empty; string [] result = new string[m.Groups[1].Captures.Count]; int ix = 0; foreach(Capture c in m.Groups[1].Captures) { result[ix++] = c.Value; } return result; }
private string[] SplitByLength(string s, int d) { List<string> stringList = new List<string>(); if (s.Length <= d) stringList.Add(s); else { int x = 0; for (; (x + d) < s.Length; x += d) { stringList.Add(s.Substring(x, d)); } stringList.Add(s.Substring(x)); } return stringList.ToArray(); }
private void button2_Click(object sender, EventArgs e) { string s = "AAABBBCCC"; string[] a = SplitByLenght(s,3); } private string[] SplitByLenght(string s, int split) { //Like using List because I can just add to it List<string> list = new List<string>(); // Integer Division int TimesThroughTheLoop = s.Length/split; for (int i = 0; i < TimesThroughTheLoop; i++) { list.Add(s.Substring(i * split, split)); } // Pickup the end of the string if (TimesThroughTheLoop * split != s.Length) { list.Add(s.Substring(TimesThroughTheLoop * split)); } return list.ToArray(); }
我有奇怪的场景,我已经分割了一个string,然后重新安排段(即颠倒),然后我连接它们,然后我需要扭转分割。 以下是@SLaks接受的答案的更新 :
/// <summary> /// Split the given string into equally-sized segments (possibly with a 'remainder' if uneven division). Optionally return the 'remainder' first. /// </summary> /// <param name="str">source string</param> /// <param name="maxLength">size of each segment (except the remainder, which will be less)</param> /// <param name="remainderFirst">if dividing <paramref name="str"/> into segments would result in a chunk smaller than <paramref name="maxLength"/> left at the end, instead take it from the beginning</param> /// <returns>list of segments within <paramref name="str"/></returns> /// <remarks>Original method at https://stackoverflow.com/questions/3008718/split-string-into-smaller-strings-by-length-variable </remarks> private static IEnumerable<string> ToSegments(string str, int maxLength, bool remainderFirst = false) { // note: `maxLength == 0` would not only not make sense, but would result in an infinite loop if(maxLength < 1) throw new ArgumentOutOfRangeException("maxLength", maxLength, "Should be greater than 0"); // correct for the infinite loop caused by a nonsensical request of `remainderFirst == true` and no remainder (`maxLength==1` or even division) if( remainderFirst && str.Length % maxLength == 0 ) remainderFirst = false; var index = 0; // note that we want to stop BEFORE we reach the end // because if it's exact we'll end up with an // empty segment while (index + maxLength < str.Length) { // do we want the 'final chunk' first or at the end? if( remainderFirst && index == 0 ) { // figure out remainder size var remainder = str.Length % maxLength; yield return str.Substring(index, remainder); index += remainder; } // normal stepthrough else { yield return str.Substring(index, maxLength); index += maxLength; } } yield return str.Substring(index); }//--- fn ToSegments
(如果maxLength==1
我也更正了原始版本中的一个错误,导致产生空的段)
- Dispatcher.CurrentDispatcher与Application.Current.Dispatcher
- 没有输出到WPF应用程序的控制台?
- 强制XmlSerializer将“DateTime”序列化为“YYYY-MM-DD hh:mm:ss”
- 如何为几个构buildconfigurationselect不同的app.config
- 如何在dynamicbutton上创builddynamicbutton点击事件?
- 如何使用reflection在.NET中调用重载的方法
- HintPath VS Visual Studio中的ReferencePath
- C#.NET + PostgreSQL
- InvalidOperationException:无法parsing“Microsoft.AspNetCore.Http.IHttpContextAccessor”types的服务