将string分成一定大小的块

假设我有一个string:

string str = "1111222233334444"; 

我怎样才能把这个string分成一些大小的块?

例如,将其分解成4个大小将返回string:

 "1111" "2222" "3333" "4444" 
 static IEnumerable<string> Split(string str, int chunkSize) { return Enumerable.Range(0, str.Length / chunkSize) .Select(i => str.Substring(i * chunkSize, chunkSize)); } 

请注意,可能需要额外的代码才能正常处理边缘情况( null或空inputstring, chunkSize == 0 ,inputstring长度不能被chunkSize整除等)。 原来的问题没有具体说明这些边缘案件的任何要求,在现实生活中,要求可能会有所不同,所以他们超出了这个答案的范围。

结合鸽子和康斯坦丁的答案…

 static IEnumerable<string> WholeChunks(string str, int chunkSize) { for (int i = 0; i < str.Length; i += chunkSize) yield return str.Substring(i, chunkSize); } 

这将适用于所有可以拆分为大量块的string,否则将抛出exception。

如果你想支持任何长度的string,你可以使用下面的代码:

 static IEnumerable<string> ChunksUpto(string str, int maxChunkSize) { for (int i = 0; i < str.Length; i += maxChunkSize) yield return str.Substring(i, Math.Min(maxChunkSize, str.Length-i)); } 

但是,OP明确表示他不需要这个; 读起来有点长,难,稍慢一些。 本着KISS和YAGNI的精神,我会select第一个选项:它可能是最有效的实现,它非常短,可读,而且重要的是,对不合格input引发exception。

为什么不循环? 这是一个很好的做法:

  string str = "111122223333444455"; int chunkSize = 4; int stringLength = str.Length; for (int i = 0; i < stringLength ; i += chunkSize) { if (i + chunkSize > stringLength) chunkSize = stringLength - i; Console.WriteLine(str.Substring(i, chunkSize)); } Console.ReadLine(); 

我不知道如何处理string不是4的因素,但不是说你不可能想到,如果一个简单的for循环做得很好,只是想知道它的动机吗? 显然,上述可以清理,甚至可以作为扩展方法。

或者如评论中提到的,那么你知道它是/ 4

 str = "1111222233334444"; for (int i = 0; i < stringLength; i += chunkSize) {Console.WriteLine(str.Substring(i, chunkSize));} 

使用正则expression式Linq

 List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}") select m.Value).ToList(); 

我觉得这更可读,但这只是个人意见。 它也可以是一个单行的)。

这是基于@dove解决scheme,但作为扩展方法实现。

优点:

  • 扩展方法
  • 涵盖angular落案件
  • 用任何字符拆分string:数字,字母,其他符号

 public static class EnumerableEx { public static IEnumerable<string> SplitBy(this string str, int chunkLength) { if (String.IsNullOrEmpty(str)) throw new ArgumentException(); if (chunkLength < 1) throw new ArgumentException(); for (int i = 0; i < str.Length; i += chunkLength) { if (chunkLength + i > str.Length) chunkLength = str.Length - i; yield return str.Substring(i, chunkLength); } } } 

用法

 var result = "bobjoecat".SplitBy(3); // bob, joe, cat 

为了简洁,删除了unit testing(请参阅前一版本 )

这是一个单线程?

 List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})", RegexOptions.Singleline)); 

有了这个正则expression式,最后一个块是否less于四个字符并不重要,因为它只查看它后面的字符。 我相信这不是最有效的解决scheme,但我只是把它扔在那里。 :d

这不是很好,它不是很快,但它的工作原理,这是一个单线,它是LINQy:

 List<string> a = text.Select((c, i) => new { Char = c, Index = i }).GroupBy(o => o.Index / 4).Select(g => new String(g.Select(o => o.Char).ToArray())).ToList(); 

我最近不得不写一些在工作中完成的东西,所以我想我会解决这个问题。 作为一个额外的好处,这个解决scheme的function提供了一种方法来分裂string在相反的方向,并且正确地处理unicode字符,如上面Marvin Pinto提到的。 所以,这里是:

 using System; using Extensions; namespace TestCSharp { class Program { static void Main(string[] args) { string asciiStr = "This is a string."; string unicodeStr = "これは文字列です。"; string[] array1 = asciiStr.Split(4); string[] array2 = asciiStr.Split(-4); string[] array3 = asciiStr.Split(7); string[] array4 = asciiStr.Split(-7); string[] array5 = unicodeStr.Split(5); string[] array6 = unicodeStr.Split(-5); } } } namespace Extensions { public static class StringExtensions { /// <summary>Returns a string array that contains the substrings in this string that are seperated a given fixed length.</summary> /// <param name="s">This string object.</param> /// <param name="length">Size of each substring. /// <para>CASE: length &gt; 0 , RESULT: String is split from left to right.</para> /// <para>CASE: length == 0 , RESULT: String is returned as the only entry in the array.</para> /// <para>CASE: length &lt; 0 , RESULT: String is split from right to left.</para> /// </param> /// <returns>String array that has been split into substrings of equal length.</returns> /// <example> /// <code> /// string s = "1234567890"; /// string[] a = s.Split(4); // a == { "1234", "5678", "90" } /// </code> /// </example> public static string[] Split(this string s, int length) { System.Globalization.StringInfo str = new System.Globalization.StringInfo(s); int lengthAbs = Math.Abs(length); if (str == null || str.LengthInTextElements == 0 || lengthAbs == 0 || str.LengthInTextElements <= lengthAbs) return new string[] { str.ToString() }; string[] array = new string[(str.LengthInTextElements % lengthAbs == 0 ? str.LengthInTextElements / lengthAbs: (str.LengthInTextElements / lengthAbs) + 1)]; if (length > 0) for (int iStr = 0, iArray = 0; iStr < str.LengthInTextElements && iArray < array.Length; iStr += lengthAbs, iArray++) array[iArray] = str.SubstringByTextElements(iStr, (str.LengthInTextElements - iStr < lengthAbs ? str.LengthInTextElements - iStr : lengthAbs)); else // if (length < 0) for (int iStr = str.LengthInTextElements - 1, iArray = array.Length - 1; iStr >= 0 && iArray >= 0; iStr -= lengthAbs, iArray--) array[iArray] = str.SubstringByTextElements((iStr - lengthAbs < 0 ? 0 : iStr - lengthAbs + 1), (iStr - lengthAbs < 0 ? iStr + 1 : lengthAbs)); return array; } } } 

此外,这里是一个图像链接到运行此代码的结果: http : //i.imgur.com/16Iih.png

这应该比使用LINQ或这里使用的其他方法更快更有效。

 public static IEnumerable<string> Splice(this string s, int spliceLength) { if (s == null) throw new ArgumentNullException("s"); if (spliceLength < 1) throw new ArgumentOutOfRangeException("spliceLength"); if (s.Length == 0) yield break; var start = 0; for (var end = spliceLength; end < s.Length; end += spliceLength) { yield return s.Substring(start, spliceLength); start = end; } yield return s.Substring(start); } 
 public static IEnumerable<IEnumerable<T>> SplitEvery<T>(this IEnumerable<T> values, int n) { var ls = values.Take(n); var rs = values.Skip(n); return ls.Any() ? Cons(ls, SplitEvery(rs, n)) : Enumerable.Empty<IEnumerable<T>>(); } public static IEnumerable<T> Cons<T>(T x, IEnumerable<T> xs) { yield return x; foreach (var xi in xs) yield return xi; } 

Jon Skeet可以使用morelinq 。 使用批处理 :

 string str = "1111222233334444"; int chunkSize = 4; var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray())); 

这将返回4个string"1111222233334444" 。 如果string长度小于或等于块大小Batch将返回string作为IEnumerable<string>的唯一元素IEnumerable<string>

输出:

 foreach (var chunk in chunks) { Console.WriteLine(chunk); } 

它会给:

 1111 2222 3333 4444 

六年后o_O

只是因为

  public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront) { var count = (int) Math.Ceiling(str.Length/(double) chunkSize); Func<int, int> start = index => remainingInFront ? str.Length - (count - index)*chunkSize : index*chunkSize; Func<int, int> end = index => Math.Min(str.Length - Math.Max(start(index), 0), Math.Min(start(index) + chunkSize - Math.Max(start(index), 0), chunkSize)); return Enumerable.Range(0, count).Select(i => str.Substring(Math.Max(start(i), 0),end(i))); } 

要么

  private static Func<bool, int, int, int, int, int> start = (remainingInFront, length, count, index, size) => remainingInFront ? length - (count - index) * size : index * size; private static Func<bool, int, int, int, int, int, int> end = (remainingInFront, length, count, index, size, start) => Math.Min(length - Math.Max(start, 0), Math.Min(start + size - Math.Max(start, 0), size)); public static IEnumerable<string> Split(this string str, int chunkSize, bool remainingInFront) { var count = (int)Math.Ceiling(str.Length / (double)chunkSize); return Enumerable.Range(0, count).Select(i => str.Substring( Math.Max(start(remainingInFront, str.Length, count, i, chunkSize), 0), end(remainingInFront, str.Length, count, i, chunkSize, start(remainingInFront, str.Length, count, i, chunkSize)) )); } 

AFAIK处理所有的边缘情况。

 Console.WriteLine(string.Join(" ", "abc".Split(2, false))); // ab c Console.WriteLine(string.Join(" ", "abc".Split(2, true))); // a bc Console.WriteLine(string.Join(" ", "a".Split(2, true))); // a Console.WriteLine(string.Join(" ", "a".Split(2, false))); // a 

如果被分块的string需要支持所有的Unicode字符,这是一个重要的提示。

如果string要支持国际字符(如𠀋 ,则使用System.Globalization.StringInfo类拆分string。 使用StringInfo,可以根据文本元素的数量来分割string。

 string internationalString = '𠀋'; 

上面的string长度为2,因为String.Length属性返回此实例中的Char对象数量,而不是Unicode字符数量。

最好,最简单和通用的答案:)。

  string originalString = "1111222233334444"; List<string> test = new List<string>(); int chunkSize = 4; // change 4 with the size of strings you want. for (int i = 0; i < originalString.Length; i = i + chunkSize) { if (originalString.Length - i >= chunkSize) test.Add(originalString.Substring(i, chunkSize)); else test.Add(originalString.Substring(i,((originalString.Length - i)))); } 
 static IEnumerable<string> Split(string str, double chunkSize) { return Enumerable.Range(0, (int) Math.Ceiling(str.Length/chunkSize)) .Select(i => new string(str .Skip(i * (int)chunkSize) .Take((int)chunkSize) .ToArray())); } 

另一种方法是:

 using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var x = "Hello World"; foreach(var i in x.ChunkString(2)) Console.WriteLine(i); } } public static class Ext{ public static IEnumerable<string> ChunkString(this string val, int chunkSize){ return val.Select((x,i) => new {Index = i, Value = x}) .GroupBy(x => x.Index/chunkSize, x => x.Value) .Select(x => string.Join("",x)); } } 

我个人更喜欢我的解决scheme:-)

它处理:

  • string长度是块大小的倍数。
  • string长度不是块大小的倍数。
  • string长度小于块大小。
  • NULL和空string(引发exception)。
  • 块大小小于1(抛出exception)。

它是作为扩展方法实现的,并且它计算事先要生成的块的数量。 它检查最后的块,因为万一文本长度不是一个倍数,它需要更短。 干净,简短,容易理解…和工作!

  public static string[] Split(this string value, int chunkSize) { if (string.IsNullOrEmpty(value)) throw new ArgumentException("The string cannot be null."); if (chunkSize < 1) throw new ArgumentException("The chunk size should be equal or greater than one."); int remainder; int divResult = Math.DivRem(value.Length, chunkSize, out remainder); int numberOfChunks = remainder > 0 ? divResult + 1 : divResult; var result = new string[numberOfChunks]; int i = 0; while (i < numberOfChunks - 1) { result[i] = value.Substring(i * chunkSize, chunkSize); i++; } int lastChunkSize = remainder > 0 ? remainder : chunkSize; result[i] = value.Substring(i * chunkSize, lastChunkSize); return result; } 

我已经稍微build立了João的解决scheme。 我所做的不同是在我的方法,你可以实际指定是否要返回数组剩余的字符,或者如果结尾字符不匹配所需的块长度是否要截断它们,我认为这是非常灵活的代码非常简单:

 using System; using System.Linq; using System.Text.RegularExpressions; namespace SplitFunction { class Program { static void Main(string[] args) { string text = "hello, how are you doing today?"; string[] chunks = SplitIntoChunks(text, 3,false); if (chunks != null) { chunks.ToList().ForEach(e => Console.WriteLine(e)); } Console.ReadKey(); } private static string[] SplitIntoChunks(string text, int chunkSize, bool truncateRemaining) { string chunk = chunkSize.ToString(); string pattern = truncateRemaining ? ".{" + chunk + "}" : ".{1," + chunk + "}"; string[] chunks = null; if (chunkSize > 0 && !String.IsNullOrEmpty(text)) chunks = (from Match m in Regex.Matches(text,pattern)select m.Value).ToArray(); return chunks; } } } 
  public static List<string> SplitByMaxLength(this string str) { List<string> splitString = new List<string>(); for (int index = 0; index < str.Length; index += MaxLength) { splitString.Add(str.Substring(index, Math.Min(MaxLength, str.Length - index))); } return splitString; } 

轻微更改以返回大小不等于块大小的零件

 public static IEnumerable<string> Split(this string str, int chunkSize) { var splits = new List<string>(); if (str.Length < chunkSize) { chunkSize = str.Length; } splits.AddRange(Enumerable.Range(0, str.Length / chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize))); splits.Add(str.Length % chunkSize > 0 ? str.Substring((str.Length / chunkSize) * chunkSize, str.Length - ((str.Length / chunkSize) * chunkSize)) : string.Empty); return (IEnumerable<string>)splits; } 

我不记得是谁给了我这个,但是效果很好。 我速度testing了许多方法来将Enumerabletypes分成组。 用法就是这样…

 List<string> Divided = Source3.Chunk(24).Select(Piece => string.Concat<char>(Piece)).ToList(); 

扩展代码看起来像这样…

 #region Chunk Logic private class ChunkedEnumerable<T> : IEnumerable<T> { class ChildEnumerator : IEnumerator<T> { ChunkedEnumerable<T> parent; int position; bool done = false; T current; public ChildEnumerator(ChunkedEnumerable<T> parent) { this.parent = parent; position = -1; parent.wrapper.AddRef(); } public T Current { get { if (position == -1 || done) { throw new InvalidOperationException(); } return current; } } public void Dispose() { if (!done) { done = true; parent.wrapper.RemoveRef(); } } object System.Collections.IEnumerator.Current { get { return Current; } } public bool MoveNext() { position++; if (position + 1 > parent.chunkSize) { done = true; } if (!done) { done = !parent.wrapper.Get(position + parent.start, out current); } return !done; } public void Reset() { // per http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx throw new NotSupportedException(); } } EnumeratorWrapper<T> wrapper; int chunkSize; int start; public ChunkedEnumerable(EnumeratorWrapper<T> wrapper, int chunkSize, int start) { this.wrapper = wrapper; this.chunkSize = chunkSize; this.start = start; } public IEnumerator<T> GetEnumerator() { return new ChildEnumerator(this); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } } private class EnumeratorWrapper<T> { public EnumeratorWrapper(IEnumerable<T> source) { SourceEumerable = source; } IEnumerable<T> SourceEumerable { get; set; } Enumeration currentEnumeration; class Enumeration { public IEnumerator<T> Source { get; set; } public int Position { get; set; } public bool AtEnd { get; set; } } public bool Get(int pos, out T item) { if (currentEnumeration != null && currentEnumeration.Position > pos) { currentEnumeration.Source.Dispose(); currentEnumeration = null; } if (currentEnumeration == null) { currentEnumeration = new Enumeration { Position = -1, Source = SourceEumerable.GetEnumerator(), AtEnd = false }; } item = default(T); if (currentEnumeration.AtEnd) { return false; } while (currentEnumeration.Position < pos) { currentEnumeration.AtEnd = !currentEnumeration.Source.MoveNext(); currentEnumeration.Position++; if (currentEnumeration.AtEnd) { return false; } } item = currentEnumeration.Source.Current; return true; } int refs = 0; // needed for dispose semantics public void AddRef() { refs++; } public void RemoveRef() { refs--; if (refs == 0 && currentEnumeration != null) { var copy = currentEnumeration; currentEnumeration = null; copy.Source.Dispose(); } } } /// <summary>Speed Checked. Works Great!</summary> public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) { if (chunksize < 1) throw new InvalidOperationException(); var wrapper = new EnumeratorWrapper<T>(source); int currentPos = 0; T ignore; try { wrapper.AddRef(); while (wrapper.Get(currentPos, out ignore)) { yield return new ChunkedEnumerable<T>(wrapper, chunksize, currentPos); currentPos += chunksize; } } finally { wrapper.RemoveRef(); } } #endregion 
 class StringHelper { static void Main(string[] args) { string str = "Hi my name is vikas bansal and my email id is bansal.vks@gmail.com"; int offSet = 10; List<string> chunks = chunkMyStr(str, offSet); Console.Read(); } static List<string> chunkMyStr(string str, int offSet) { List<string> resultChunks = new List<string>(); for (int i = 0; i < str.Length; i += offSet) { string temp = str.Substring(i, (str.Length - i) > offSet ? offSet : (str.Length - i)); Console.WriteLine(temp); resultChunks.Add(temp); } return resultChunks; } } 

基于其他海报答案,以及一些使用样本:

 public static string FormatSortCode(string sortCode) { return ChunkString(sortCode, 2, "-"); } public static string FormatIBAN(string iban) { return ChunkString(iban, 4, "&nbsp;&nbsp;"); } private static string ChunkString(string str, int chunkSize, string separator) { var b = new StringBuilder(); var stringLength = str.Length; for (var i = 0; i < stringLength; i += chunkSize) { if (i + chunkSize > stringLength) chunkSize = stringLength - i; b.Append(str.Substring(i, chunkSize)); if (i+chunkSize != stringLength) b.Append(separator); } return b.ToString(); } 

使用IX库中的Buffer扩展

  static IEnumerable<string> Split( this string str, int chunkSize ) { return str.Buffer(chunkSize).Select(l => String.Concat(l)); } 

这也可以这样做

  string actualString = "1111222233334444"; var listResult = new List<string>(); int groupingLength = actualString.Length % 4; if (groupingLength > 0) listResult.Add(actualString.Substring(0, groupingLength)); for (int i = groupingLength; i < actualString.Length; i += 4) { listResult.Add(actualString.Substring(i, 4)); } foreach(var res in listResult) { Console.WriteLine(res); } Console.Read(); 

修改(现在它接受任何非空string任何积极块大小) 康斯坦丁Spirin的解决scheme:

 public static IEnumerable<String> Split(String value, int chunkSize) { if (null == value) throw new ArgumentNullException("value"); else if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize", "Chunk size should be positive"); return Enumerable .Range(0, value.Length / chunkSize + ((value.Length % chunkSize) == 0 ? 0 : 1)) .Select(index => (index + 1) * chunkSize < value.Length ? value.Substring(index * chunkSize, chunkSize) : value.Substring(index * chunkSize)); } 

testing:

  String source = @"ABCDEF"; // "ABCD,EF" String test1 = String.Join(",", Split(source, 4)); // "AB,CD,EF" String test2 = String.Join(",", Split(source, 2)); // "ABCDEF" String test3 = String.Join(",", Split(source, 123)); 

如果有必要分裂几个不同的长度:例如,你有指定格式的date和时间stringstrangeStr = "07092016090532"; 07092016090532(date:07.09.2016时间:09:05:32)

 public static IEnumerable<string> SplitBy(this string str, int[] chunkLength) { if (String.IsNullOrEmpty(str)) throw new ArgumentException(); int i = 0; for (int j = 0; j < chunkLength.Length; j++) { if (chunkLength[j] < 1) throw new ArgumentException(); if (chunkLength[j] + i > str.Length) { chunkLength[j] = str.Length - i; } yield return str.Substring(i, chunkLength[j]); i += chunkLength[j]; } } 

使用:

 string[] dt = strangeStr.SplitBy(new int[] { 2, 2, 4, 2, 2, 2, 2 }).ToArray(); 

简而言之:

 // this means match a space or not a space (anything) up to 4 characters var lines = Regex.Matches(str, @"[\s\S]{0,4}").Cast<Match>().Select(x => x.Value); 
 List<string> SplitString(int chunk, string input) { List<string> list = new List<string>(); int cycles = input.Length / chunk; if (input.Length % chunk != 0) cycles++; for (int i = 0; i < cycles; i++) { try { list.Add(input.Substring(i * chunk, chunk)); } catch { list.Add(input.Substring(i * chunk)); } } return list; }