สมมติว่าฉันมีสตริง:
string str = "1111222233334444";
ฉันจะแบ่งสตริงนี้เป็นชิ้นขนาดได้อย่างไร
เช่นการแบ่งเป็น 4 ขนาดจะคืนค่าสตริง:
"1111"
"2222"
"3333"
"4444"
สมมติว่าฉันมีสตริง:
string str = "1111222233334444";
ฉันจะแบ่งสตริงนี้เป็นชิ้นขนาดได้อย่างไร
เช่นการแบ่งเป็น 4 ขนาดจะคืนค่าสตริง:
"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
หรือสตริงอินพุตว่างchunkSize == 0
, ความยาวสตริงอินพุตที่ไม่สามารถหารด้วยchunkSize
ฯลฯ ) คำถามดั้งเดิมไม่ได้ระบุข้อกำหนดใด ๆ สำหรับกรณีขอบเหล่านี้และในชีวิตจริงข้อกำหนดอาจแตกต่างกันไปดังนั้นจึงไม่อยู่ในขอบเขตของคำตอบนี้
(i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize
สิ่งที่ชอบ: ปัญหาเพิ่มเติมคือฟังก์ชั่นนี้ไม่ได้พิจารณาว่า str เป็นโมฆะ สิ่งนี้สามารถแก้ไขได้โดยการห่อคำสั่งการส่งคืนทั้งหมดไว้ในนิพจน์ประกอบ(str != null) ? ... : Enumerable.Empty<String>();
ไปด้วย:
str.Length / chunkSize
เป็นdouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
StringLength % 4 will always be 0
เริ่มต้นกระทู้กล่าวว่าในความคิดเห็นว่า หากLinq
ไม่เข้าใจง่ายมีคำตอบอื่น ๆ ที่ใช้ลูปและอัตราผลตอบแทน ทุกคนสามารถเลือกวิธีการแก้ปัญหาที่เธอชอบที่สุดได้ฟรี คุณสามารถโพสต์รหัสของคุณเป็นคำตอบและผู้คนจะลงคะแนนอย่างมีความสุข
ในการรวมกันของคำตอบของนกพิราบ + Konstatin ...
static IEnumerable<string> WholeChunks(string str, int chunkSize) {
for (int i = 0; i < str.Length; i += chunkSize)
yield return str.Substring(i, chunkSize);
}
สิ่งนี้จะใช้ได้กับสตริงทั้งหมดที่สามารถแบ่งออกเป็นจำนวนเต็มทั้งหมดและจะมีข้อยกเว้นเป็นอย่างอื่น
หากคุณต้องการสนับสนุนสตริงที่มีความยาวเท่าใดก็ได้คุณสามารถใช้รหัสต่อไปนี้:
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 ฉันมีตัวเลือกแรก: อาจเป็นการนำไปใช้ที่มีประสิทธิภาพที่สุดและสั้นมากอ่านง่ายและที่สำคัญโยนข้อยกเว้นสำหรับอินพุตที่ไม่เป็นไปตามข้อกำหนด
ทำไมไม่ลูป นี่คือสิ่งที่จะทำได้ค่อนข้างดี:
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();
ฉันไม่รู้ว่าคุณจะจัดการกับกรณีที่สตริงไม่ใช่ปัจจัย 4 แต่ไม่ได้บอกว่าคุณไม่คิดว่าจะเป็นไปได้เพียงแค่สงสัยว่ามีแรงจูงใจสำหรับมันหรือไม่ถ้าการวนรอบง่ายทำได้ดีมาก? เห็นได้ชัดว่าข้างต้นสามารถทำความสะอาดและแม้กระทั่งเป็นวิธีการขยาย
หรือตามที่ระบุไว้ในความคิดเห็นคุณรู้ว่ามัน / 4 แล้ว
str = "1111222233334444";
for (int i = 0; i < stringLength; i += chunkSize)
{Console.WriteLine(str.Substring(i, chunkSize));}
int chunkSize = 4
ออกไปนอกวง มันจะถูกแก้ไขในรอบสุดท้ายเท่านั้น
i += chunkSize
แทน
str.Length
ออกจากวงและเป็นตัวแปรท้องถิ่น เครื่องมือเพิ่มประสิทธิภาพ C # อาจจะมีความยาวของแถวเรียงแบบอินไลน์ แต่ฉันคิดว่าโค้ดตามที่เขียนจะทำการเรียกเมธอดบนทุกลูปซึ่งไม่มีประสิทธิภาพเนื่องจากขนาดstr
ไม่เคยเปลี่ยนแปลง
ใช้นิพจน์ทั่วไปและLinq :
List<string> groups = (from Match m in Regex.Matches(str, @"\d{4}")
select m.Value).ToList();
ฉันพบว่าสิ่งนี้สามารถอ่านได้มากขึ้น แต่เป็นเพียงความเห็นส่วนตัว นอกจากนี้ยังอาจเป็นหนึ่งซับ:)
\d
ตัวละครคลาสด้วยและเพื่อระบุ.
RegexOptions.Singleline
สิ่งนี้ขึ้นอยู่กับโซลูชัน @doveแต่นำมาใช้เป็นวิธีส่วนขยาย
ประโยชน์ที่ได้รับ:
รหัส
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
การทดสอบหน่วยถอดออกมาเพื่อความกะทัดรัด (ดูการแก้ไขก่อนหน้านี้ )
if (str.Length == 0) yield return String.Empty; else { for... }
IEnumerable
ไปยังแถวลำดับโดยเฉพาะอย่างยิ่งไม่ใช่โดยปริยาย
Chunkify
.. ไม่ใช่ของฉันฉันจำไม่ได้ว่าฉันเห็นชื่อนั้นที่ไหน แต่รู้สึกดีกับฉันมาก
วิธีนี้สำหรับซับหนึ่งหรือไม่
List<string> result = new List<string>(Regex.Split(target, @"(?<=\G.{4})", RegexOptions.Singleline));
ด้วย regex นี้มันไม่สำคัญว่าอันสุดท้ายจะน้อยกว่าสี่ตัวอักษรเพราะมันจะมองที่ตัวอักษรด้านหลังเท่านั้น
ฉันแน่ใจว่านี่ไม่ใช่วิธีที่มีประสิทธิภาพที่สุด แต่ฉันต้องโยนมันทิ้งไป
target.Lenght % ChunckSize == 0
ที่ส่งคืนแถวว่างเพิ่มเติมเช่นList<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
มันไม่สวยและไม่เร็ว แต่ใช้งานได้มันเป็นแบบเส้นเดียวและเป็น 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();
ToCharArray
ไม่จำเป็นตั้งแต่มีstring
IEnumerable<char>
เมื่อเร็ว ๆ นี้ฉันต้องเขียนบางสิ่งบางอย่างที่ประสบความสำเร็จในที่ทำงานดังนั้นฉันคิดว่าฉันจะโพสต์วิธีแก้ไขปัญหานี้ ในฐานะโบนัสเพิ่มเติมฟังก์ชันการทำงานของโซลูชันนี้มีวิธีการแยกสตริงในทิศทางตรงกันข้ามและจะจัดการอักขระ 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 > 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 < 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
{str.ToString()}
คำสั่ง IF สุดท้ายของคุณ คุณแน่ใจว่าคุณไม่ได้หมายความว่าstr.String
? ฉันมีปัญหากับรหัสข้างต้นทำการเปลี่ยนแปลงนั้นและทุกอย่างทำงานได้
นี่ควรจะเร็วกว่าและมีประสิทธิภาพมากกว่าการใช้ 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;
}
คุณสามารถใช้morelinqโดย Jon Skeet ใช้แบทช์ที่ชอบ:
string str = "1111222233334444";
int chunkSize = 4;
var chunks = str.Batch(chunkSize).Select(r => new String(r.ToArray()));
นี้จะกลับ 4 "1111222233334444"
ชิ้นสำหรับสตริง หากความยาวสตริงน้อยกว่าหรือเท่ากับขนาดก้อนBatch
จะส่งคืนสตริงเป็นองค์ประกอบเดียวของIEnumerable<string>
สำหรับเอาท์พุท:
foreach (var chunk in chunks)
{
Console.WriteLine(chunk);
}
และมันจะให้:
1111
2222
3333
4444
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));
}
}
หกปีต่อมา 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
ง่ายและสั้น:
// 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);
.
?
static IEnumerable<string> Split(string str, int chunkSize)
{
IEnumerable<string> retVal = Enumerable.Range(0, str.Length / chunkSize)
.Select(i => str.Substring(i * chunkSize, chunkSize))
if (str.Length % chunkSize > 0)
retVal = retVal.Append(str.Substring(str.Length / chunkSize * chunkSize, str.Length % chunkSize));
return retVal;
}
มันจัดการอย่างถูกต้องความยาวสตริงที่ไม่หารหารด้วย chunkSize
โปรดทราบว่าอาจต้องใช้รหัสเพิ่มเติมเพื่อจัดการกับขอบเคส (สตริงอินพุตว่างหรือสตริงว่าง chunkSize == 0)
เคล็ดลับสำคัญหากสตริงที่กำลังถูก chunked จำเป็นต้องสนับสนุนอักขระ Unicode ทั้งหมด
หากสตริงคือการสนับสนุนอักขระสากลเช่น𠀋
แล้วแยกสตริงโดยใช้คลาส System.Globalization.StringInfo ใช้ StringInfo คุณสามารถแยกสตริงตามจำนวนขององค์ประกอบข้อความ
string internationalString = '𠀋';
สตริงด้านบนมีความยาว 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))));
}
Substring
originalString.Substring(i)
นอกจากนี้คุณสามารถใช้>
แทน>=
ในการตรวจสอบของคุณ
โดยส่วนตัวแล้วฉันชอบโซลูชันของฉัน :-)
มันจัดการ:
มันถูกนำมาใช้เป็นวิธีการขยายและคำนวณจำนวนชิ้นที่จะสร้างไว้ล่วงหน้า มันจะตรวจสอบอันสุดท้ายเพราะในกรณีที่ความยาวข้อความไม่ได้หลายจะต้องสั้นลง สะอาดสั้นเข้าใจง่าย ... และใช้งานได้!
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;
}
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;
}
ฉันคิดว่านี่เป็นคำตอบที่ตรงไปตรงมา:
public static IEnumerable<string> Split(this string str, int chunkSize)
{
if(string.IsNullOrEmpty(str) || chunkSize<1)
throw new ArgumentException("String can not be null or empty and chunk size should be greater than zero.");
var chunkCount = str.Length / chunkSize + (str.Length % chunkSize != 0 ? 1 : 0);
for (var i = 0; i < chunkCount; i++)
{
var startIndex = i * chunkSize;
if (startIndex + chunkSize >= str.Length)
yield return str.Substring(startIndex);
else
yield return str.Substring(startIndex, chunkSize);
}
}
และครอบคลุมกรณีขอบ
ฉันรู้ว่าคำถามมีอายุหลายปี แต่นี่คือการใช้ Rx มันจัดการlength % chunkSize != 0
ปัญหาออกจากกล่อง:
public static IEnumerable<string> Chunkify(this string input, int size)
{
if(size < 1)
throw new ArgumentException("size must be greater than 0");
return input.ToCharArray()
.ToObservable()
.Buffer(size)
.Select(x => new string(x.ToArray()))
.ToEnumerable();
}
ฉันสร้างโซลูชันของJoãoขึ้นมาเล็กน้อย สิ่งที่ฉันทำแตกต่างกันคือในวิธีการของฉันคุณสามารถระบุได้ว่าคุณต้องการคืนค่าอาเรย์ด้วยอักขระที่เหลือหรือว่าคุณต้องการที่จะตัดทอนถ้าอักขระสุดท้ายไม่ตรงกับความยาวของชิ้นที่ต้องการฉันคิดว่ามันค่อนข้างยืดหยุ่นและ รหัสค่อนข้างตรงไปตรงมา:
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;
}
List
เพื่อIEnumerable
; สิ่งที่ทำคือซ่อนฟังก์ชันเฉพาะรายการที่คุณอาจต้องการใช้ ไม่มีข้อเสียคือสิ่งใด ๆ List
ที่จะเพียงแค่กลับมา
ฉันจำไม่ได้ว่าใครให้สิ่งนี้กับฉัน แต่มันใช้งานได้ดี ฉันทดสอบความเร็วหลายวิธีเพื่อแบ่งประเภทนับออกเป็นกลุ่ม การใช้งานจะเป็นเช่นนี้ ...
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;
}
}
i += offSet
เป็นfor
นิพจน์ของคุณ
แก้ไข (ตอนนี้ก็ยอมรับใด ๆ null ไม่ใช่string
และใด ๆในเชิงบวกchunkSize
) คอนสแตนติ Spirinแก้ปัญหา 's:
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));
}
แบบทดสอบ:
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));
static List<string> GetChunks(string value, int chunkLength)
{
var res = new List<string>();
int count = (value.Length / chunkLength) + (value.Length % chunkLength > 0 ? 1 : 0);
Enumerable.Range(0, count).ToList().ForEach(f => res.Add(value.Skip(f * chunkLength).Take(chunkLength).Select(z => z.ToString()).Aggregate((a,b) => a+b)));
return res;
}
ตามคำตอบโปสเตอร์อื่น ๆ พร้อมกับตัวอย่างการใช้งาน:
public static string FormatSortCode(string sortCode)
{
return ChunkString(sortCode, 2, "-");
}
public static string FormatIBAN(string iban)
{
return ChunkString(iban, 4, " ");
}
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();
}
การใช้ส่วนขยายบัฟเฟอร์จากไลบรารีทรงเครื่อง
static IEnumerable<string> Split( this string str, int chunkSize )
{
return str.Buffer(chunkSize).Select(l => String.Concat(l));
}