Mengapa menggunakan LINQ atau regex ketika fungsi manipulasi string standar C # dapat melakukan ini dengan sedikit usaha dan lebih banyak kecepatan? Juga, apa yang terjadi jika string memiliki jumlah karakter ganjil?
Ian Kemp
7
"Saya ingin menghindari loop" - mengapa?
Mitch Wheat
12
Menggunakan loop sederhana jelas merupakan hal yang memberikan kinerja terbaik.
Guffa
4
nichesoftware.co.nz/blog/200909/linq-vs-loop-performance adalah perbandingan yang cukup bagus antara linq dan perulangan aktual pada array. Saya ragu Anda akan menemukan linq lebih cepat daripada kode yang ditulis secara manual karena terus memanggil delegasi run-time yang sulit untuk dioptimalkan. Linq lebih menyenangkan :) :)
Blindy
2
Apakah Anda menggunakan LINQ atau regex, loop masih ada.
Harap dicatat bahwa kode tambahan mungkin diperlukan untuk menangani case edge dengan anggun ( nullatau mengosongkan string input,, chunkSize == 0panjang string input tidak dapat dibagi oleh chunkSize, dll.). Pertanyaan asli tidak menentukan persyaratan untuk kasus tepi ini dan dalam kehidupan nyata persyaratan mungkin bervariasi sehingga mereka berada di luar cakupan jawaban ini.
@Harry, tangkapan bagus! Ini dapat diperbaiki dengan ekspresi ter-drop-in pada parameter count dari substring. Sesuatu seperti: (i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize. Masalah tambahan adalah bahwa fungsi ini tidak memperhitungkan str menjadi nol. Ini bisa diperbaiki dengan membungkus pernyataan kembali seluruh dalam ekspresi terner lain: (str != null) ? ... : Enumerable.Empty<String>();.
Drew Spickes
7
Ini dekat, tetapi tidak seperti 30 upvoter sebelumnya, saya harus mengubah batas jumlah loop Range dari str.Length / chunkSizekedouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
gap
4
@KonstantinSpirin Saya setuju jika kodenya bekerja. Ini hanya menangani case di mana string adalah kelipatan dari chunkSize, sisa string hilang. Tolong ubah. Perlu diingat juga bahwa LINQ dan sulapnya tidak mudah dipahami oleh seseorang yang hanya ingin melihat solusi untuk masalah ini. Seseorang sekarang harus memahami apa yang dilakukan fungsi Enumerable.Range () dan .Select (). Saya tidak akan berdebat bahwa Anda harus memiliki pemahaman tentang itu untuk menulis kode C # /. NET karena fungsi-fungsi ini telah di BCL selama bertahun-tahun sekarang.
CodeMonkeyKing
6
Topik pemula mengatakan dalam komentar itu StringLength % 4 will always be 0. Jika Linqtidak mudah dipahami maka ada jawaban lain yang menggunakan loop dan hasil. Siapa pun bebas memilih solusi yang paling disukainya. Anda dapat memposting kode Anda sebagai jawaban dan orang-orang akan dengan senang hati memilihnya.
Konstantin Spirin
3
Enumerable.Range (0, (str.Length + chunkSize - 1) / chunkSize) .Pilih (i => str.Substring (i * chunkSize, Math.Min (str.Length - i * chunkSize, chunkSize))
Sten Petrov
135
Dalam kombinasi jawaban dove + Konstatin ...
staticIEnumerable<string>WholeChunks(string str,int chunkSize){for(int i =0; i < str.Length; i += chunkSize)yieldreturn str.Substring(i, chunkSize);}
Ini akan bekerja untuk semua string yang dapat dipecah menjadi sejumlah besar potongan, dan akan melemparkan pengecualian.
Jika Anda ingin mendukung string dengan panjang apa pun, Anda dapat menggunakan kode berikut:
staticIEnumerable<string>ChunksUpto(string str,int maxChunkSize){for(int i =0; i < str.Length; i += maxChunkSize)yieldreturn str.Substring(i,Math.Min(maxChunkSize, str.Length-i));}
Namun, OP secara eksplisit menyatakan dia tidak membutuhkan ini; itu agak lebih panjang dan sulit dibaca, sedikit lebih lambat. Dalam semangat KISS dan YAGNI, saya akan memilih opsi pertama: itu mungkin implementasi yang seefisien mungkin, dan sangat singkat, mudah dibaca, dan, yang penting, melempar pengecualian untuk input yang tidak sesuai.
+1 bernilai anggukan. agak memukul paku di kepala. dia mencari sytnax ringkas dan Anda juga memberikan (mungkin) kinerja yang lebih baik.
dove
7
Dan jika Anda menjadikannya "static ... Chunk (str ini, int chunkSize) {" Anda bahkan punya satu C "baru" lagi -Fitur di dalamnya. Maka Anda dapat menulis "1111222233334444" .Chunk (4).
MartinStettner
1
@ MartinStettner: Itu tentu ide yang bagus jika ini adalah operasi yang umum.
Eamon Nerbonne
Anda hanya harus memasukkan kode yang terakhir. Yang pertama mengharuskan Anda memahami dan menguji untuk string menjadi kelipatan dari ukuran chunk sebelum menggunakan, atau memahami bahwa string tidak akan mengembalikan sisa string.
CodeMonkeyKing
Pertanyaan OP tidak menjelaskan apakah dia membutuhkan fungsionalitas itu. Solusi pertama lebih sederhana, lebih cepat dan andal gagal dengan pengecualian jika string tidak dapat dibagi secara merata ke ukuran chunk yang ditentukan. Saya setuju bahwa mengembalikan hasil "salah" akan menjadi buruk, tetapi bukan itu yang dilakukannya - itu hanya melempar pengecualian, jadi saya akan setuju jika menggunakannya jika Anda dapat hidup dengan batasan.
Eamon Nerbonne
56
Kenapa tidak loop? Inilah sesuatu yang akan melakukannya dengan cukup baik:
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();
Saya tidak tahu bagaimana Anda akan berurusan dengan kasus di mana string bukan faktor 4, tetapi tidak mengatakan Anda ide tidak mungkin, hanya bertanya-tanya motivasi untuk itu jika sederhana untuk loop melakukannya dengan sangat baik? Jelas di atas bisa dibersihkan dan bahkan dimasukkan sebagai metode perpanjangan.
Atau seperti yang disebutkan dalam komentar, Anda tahu itu / 4 lalu
str ="1111222233334444";for(int i =0; i < stringLength; i += chunkSize){Console.WriteLine(str.Substring(i, chunkSize));}
Anda dapat menarik int chunkSize = 4keluar dari loop. Itu hanya akan dimodifikasi pada pass terakhir.
John Feminella
Memberi +1 untuk solusi sederhana dan efektif - ini adalah bagaimana saya akan melakukannya, meskipun saya akan menggunakannya i += chunkSizesebagai gantinya.
Ian Kemp
Mungkin sedikit berdalih, tetapi Anda mungkin juga harus menarik str.Lengthkeluar dari loop dan ke dalam variabel lokal. Pengoptimal C # mungkin dapat inline panjang array, tapi saya pikir kode seperti yang tertulis akan melakukan pemanggilan metode pada setiap loop, yang tidak efisien, karena ukuran strtidak pernah berubah.
Daniel Pryden
@Aniel, taruh idemu di sana. meskipun saya tidak yakin bahwa ini tidak akan dihitung pada saat runtime, tapi itu pertanyaan lain;)
dove
@Daniel kembali ke sini, cukup yakin bahwa optimasi ini akan diekstraksi oleh kompiler.
dove
41
Menggunakan ekspresi reguler dan Linq :
List<string> groups =(fromMatch m inRegex.Matches(str,@"\d{4}")select m.Value).ToList();
Saya menemukan ini lebih mudah dibaca, tetapi itu hanya pendapat pribadi. Ini juga bisa menjadi satu-baris:).
Ubah pola menjadi @ "\ d {1,4}" dan itu berfungsi untuk panjang string apa pun. :)
Guffa
3
+1 Meskipun ini lebih lambat daripada solusi lain, itu pasti sangat mudah dibaca. Tidak jelas bagi saya apakah OP membutuhkan angka atau karakter yang berubah-ubah; mungkin akan bijaksana untuk mengganti \dkelas karakter dengan a .dan untuk menentukan RegexOptions.Singleline.
Eamon Nerbonne
2
atau hanya Regex.Matches (s, @ "\ d {1,4}"). Pilih (m => m.Value) .ToList (); Saya tidak pernah mendapatkan poin dari sintaks alternatif ini yang hanya berfungsi untuk mengaburkan bahwa kita menggunakan metode ekstensi.
The Dag
38
Ini didasarkan pada solusi @dove tetapi diimplementasikan sebagai metode ekstensi.
Manfaat:
Metode ekstensi
Meliputi kasing sudut
Pisahkan string dengan karakter apa pun: angka, huruf, simbol lainnya
Kode
publicstaticclassEnumerableEx{publicstaticIEnumerable<string>SplitBy(thisstring str,int chunkLength){if(String.IsNullOrEmpty(str))thrownewArgumentException();if(chunkLength <1)thrownewArgumentException();for(int i =0; i < str.Length; i += chunkLength){if(chunkLength + i > str.Length)
chunkLength = str.Length- i;yieldreturn str.Substring(i, chunkLength);}}}
Pemakaian
var result ="bobjoecat".SplitBy(3);// bob, joe, cat
Solusi yang menarik, tetapi demi menghindari cek di luar nol pada input, tampaknya lebih logis untuk mengizinkan string kosong untuk hanya mengembalikan bagian string-kosong tunggal:if (str.Length == 0) yield return String.Empty; else { for... }
Catatan: contoh penggunaan Anda salah. Anda tidak bisa hanya menggunakan IEnumerablearray, terutama tidak secara implisit.
Nyerguds
Saya pribadi suka menyebut metode itu Chunkify .. Itu bukan milik saya, saya tidak ingat di mana saya melihat nama itu, tetapi rasanya sangat menyenangkan bagi saya
quetzalcoatl
20
Bagaimana ini untuk satu-liner?
List<string> result =newList<string>(Regex.Split(target,@"(?<=\G.{4})",RegexOptions.Singleline));
Dengan regex ini tidak masalah jika potongan terakhir kurang dari empat karakter, karena hanya pernah melihat karakter di belakangnya.
Saya yakin ini bukan solusi yang paling efisien, tetapi saya harus membuangnya di sana.
dalam kasus target.Lenght % ChunckSize == 0itu mengembalikan baris kosong tambahan misalnyaList<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
fubo
9
Itu tidak cantik dan tidak cepat, tetapi bekerja, ini satu-liner dan itu LINQy:
List<string> a = text.Select((c, i)=>new{Char= c,Index= i }).GroupBy(o => o.Index/4).Select(g =>newString(g.Select(o => o.Char).ToArray())).ToList();
Apakah dijamin bahwa GroupBy mempertahankan urutan elemen?
Konstantin Spirin
ToCharArraytidak perlu karena stringitu IEnumerable<char>.
juharr
8
Baru-baru ini saya harus menulis sesuatu yang menyelesaikan ini di tempat kerja, jadi saya pikir saya akan memposting solusi saya untuk masalah ini. Sebagai bonus tambahan, fungsionalitas dari solusi ini menyediakan cara untuk membagi string ke arah yang berlawanan dan itu benar menangani karakter unicode seperti yang disebutkan sebelumnya oleh Marvin Pinto di atas. Jadi begini:
using System;
using Extensions;
namespace TestCSharp{classProgram{staticvoidMain(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{publicstaticclassStringExtensions{/// <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> publicstaticstring[]Split(thisstring s,int length){System.Globalization.StringInfo str =newSystem.Globalization.StringInfo(s);int lengthAbs =Math.Abs(length);if(str ==null|| str.LengthInTextElements==0|| lengthAbs ==0|| str.LengthInTextElements<= lengthAbs)returnnewstring[]{ str.ToString()};string[]array=newstring[(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));returnarray;}}}
Saya melihat ada masalah dengan kode ini. Anda memiliki {str.ToString()}di akhir pernyataan IF pertama Anda. Apakah Anda yakin tidak bermaksud jahat str.String? Saya punya masalah dengan kode di atas, membuat perubahan itu, dan semuanya berfungsi.
gunr2171
@ gunr2171 Tampaknya jika str == null, baris itu juga akan memberikan NullReferenceException.
John Zabroski
5
Ini harus jauh lebih cepat dan lebih efisien daripada menggunakan LINQ atau pendekatan lain yang digunakan di sini.
publicstaticIEnumerable<string>Splice(thisstring s,int spliceLength){if(s ==null)thrownewArgumentNullException("s");if(spliceLength <1)thrownewArgumentOutOfRangeException("spliceLength");if(s.Length==0)yieldbreak;var start =0;for(var end = spliceLength; end < s.Length; end += spliceLength){yieldreturn s.Substring(start, spliceLength);
start = end;}yieldreturn s.Substring(start);}
Ini terlihat seperti pengecekan awal, tetapi tidak. Anda tidak mendapatkan kesalahan sampai Anda mulai menghitung enumerable. Anda perlu memecah fungsi Anda menjadi dua bagian, di mana bagian pertama melakukan pengecekan argumen, dan kemudian mengembalikan hasil bagian pribadi kedua yang melakukan enumerasi.
ErikE
4
publicstaticIEnumerable<IEnumerable<T>>SplitEvery<T>(thisIEnumerable<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>>();}publicstaticIEnumerable<T>Cons<T>(T x,IEnumerable<T> xs){yieldreturn x;foreach(var xi in xs)yieldreturn xi;}
Ini akan mengembalikan 4 potongan untuk string "1111222233334444". Jika panjang string kurang dari atau sama dengan ukuran chunkBatch akan mengembalikan string sebagai satu-satunya elemenIEnumerable<string>
Untuk output:
foreach(var chunk in chunks){Console.WriteLine(chunk);}
using System;
using System.Collections.Generic;
using System.Linq;publicclassProgram{publicstaticvoidMain(){var x ="Hello World";foreach(var i in x.ChunkString(2))Console.WriteLine(i);}}publicstaticclassExt{publicstaticIEnumerable<string>ChunkString(thisstring 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));}}
Console.WriteLine(string.Join(" ","abc".Split(2,false)));// ab cConsole.WriteLine(string.Join(" ","abc".Split(2,true)));// a bcConsole.WriteLine(string.Join(" ","a".Split(2,true)));// aConsole.WriteLine(string.Join(" ","a".Split(2,false)));// a
Bagaimana dengan kasus tepi "input adalah string kosong"? Saya berharap, sama seperti dengan Split, untuk mengembalikan IEnumerable dengan entri string kosong tunggal.
Nyerguds
3
Sederhana dan pendek:
// this means match a space or not a space (anything) up to 4 charactersvar lines =Regex.Matches(str,@"[\s\S]{0,4}").Cast<Match>().Select(x => x.Value);
Tip penting jika string yang sedang dipotong perlu untuk mendukung semua karakter Unicode.
Jika string ini untuk mendukung karakter internasional seperti 𠀋, maka pisahkan string menggunakan kelas System.Globalization.StringInfo. Menggunakan StringInfo, Anda dapat membagi string berdasarkan jumlah elemen teks.
string internationalString ='𠀋';
String di atas memiliki Panjang 2, karena String.Lengthproperti mengembalikan jumlah objek Char dalam contoh ini, bukan jumlah karakter Unicode.
string originalString ="1111222233334444";List<string> test =newList<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))));}
Menghitung panjang pada baris terakhir adalah redundan, cukup gunakan Substringoverload yang tidak memerlukan parameter panjang originalString.Substring(i). Anda juga bisa menggunakannya >sebagai ganti >=cek Anda.
Racil Hilan
@RacilHilan Saya akan menguji perubahan kode dengan saran Anda dan memperbarui jawabannya. Saya senang seseorang dengan reputasi baik punya waktu untuk meninjau kode saya. :) Terima kasih, Sandeep
Sandeep Kushwah
2
Secara pribadi saya lebih suka solusi saya :-)
Ini menangani:
Panjang string yang merupakan kelipatan dari ukuran chunk.
Panjang string yang TIDAK merupakan kelipatan dari ukuran chunk.
Panjang string yang lebih kecil dari ukuran chunk.
NULL dan string kosong (melempar pengecualian).
Ukuran potongan lebih kecil dari 1 (melempar pengecualian).
Ini diimplementasikan sebagai metode ekstensi, dan menghitung jumlah potongan yang akan dihasilkan sebelumnya. Ini memeriksa potongan terakhir karena jika panjang teks tidak banyak itu perlu lebih pendek. Bersih, pendek, mudah dimengerti ... dan berfungsi!
publicstaticstring[]Split(thisstringvalue,int chunkSize){if(string.IsNullOrEmpty(value))thrownewArgumentException("The string cannot be null.");if(chunkSize <1)thrownewArgumentException("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 =newstring[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;}
Saya suka jawaban ini banyak, tetapi mungkin Anda harus menggunakan if ((i +1) * chunk> = input.Length) daripada mencoba / menangkap karena pengecualian untuk kasus luar biasa.
nelsontruran
2
Saya pikir ini adalah jawaban langsung:
publicstaticIEnumerable<string>Split(thisstring str,int chunkSize){if(string.IsNullOrEmpty(str)|| chunkSize<1)thrownewArgumentException("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)yieldreturn str.Substring(startIndex);elseyieldreturn str.Substring(startIndex, chunkSize);}}
Saya tahu pertanyaan sudah berumur bertahun-tahun, tetapi ini adalah implementasi Rx. Ini menangani length % chunkSize != 0masalah di luar kotak:
publicstaticIEnumerable<string>Chunkify(thisstring input,int size){if(size <1)thrownewArgumentException("size must be greater than 0");return input.ToCharArray().ToObservable().Buffer(size).Select(x =>newstring(x.ToArray())).ToEnumerable();}
Saya sedikit membangun solusi João. Apa yang saya lakukan secara berbeda adalah dalam metode saya, Anda benar-benar dapat menentukan apakah Anda ingin mengembalikan array dengan karakter yang tersisa atau apakah Anda ingin memotongnya jika karakter akhir tidak cocok dengan panjang chunk yang diperlukan, saya pikir itu cukup fleksibel dan kode cukup mudah:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace SplitFunction{classProgram{staticvoidMain(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();}privatestaticstring[]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 =(fromMatch m inRegex.Matches(text,pattern)select m.Value).ToArray();return chunks;}}}
publicstaticList<string>SplitByMaxLength(thisstring str){List<string> splitString =newList<string>();for(int index =0; index < str.Length; index +=MaxLength){
splitString.Add(str.Substring(index,Math.Min(MaxLength, str.Length- index)));}return splitString;}
Tidak yakin saya melihat penggunaan back-casting itu Listuntuk IEnumerable; semua yang dilakukan adalah menyembunyikan fungsi khusus Daftar yang mungkin ingin Anda gunakan. Tidak ada kerugian apa pun untuk hanya mengembalikan List.
Nyerguds
1
Saya tidak ingat siapa yang memberi saya ini, tetapi itu bekerja dengan baik. Saya mempercepat menguji sejumlah cara untuk memecah tipe Enumerable ke dalam kelompok. Penggunaannya akan seperti ini ...
classStringHelper{staticvoidMain(string[] args){string str ="Hi my name is vikas bansal and my email id is [email protected]";int offSet =10;List<string> chunks = chunkMyStr(str, offSet);Console.Read();}staticList<string> chunkMyStr(string str,int offSet){List<string> resultChunks =newList<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;}}
Jawaban:
Harap dicatat bahwa kode tambahan mungkin diperlukan untuk menangani case edge dengan anggun (
null
atau mengosongkan string input,,chunkSize == 0
panjang string input tidak dapat dibagi olehchunkSize
, dll.). Pertanyaan asli tidak menentukan persyaratan untuk kasus tepi ini dan dalam kehidupan nyata persyaratan mungkin bervariasi sehingga mereka berada di luar cakupan jawaban ini.sumber
(i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize
. Masalah tambahan adalah bahwa fungsi ini tidak memperhitungkan str menjadi nol. Ini bisa diperbaiki dengan membungkus pernyataan kembali seluruh dalam ekspresi terner lain:(str != null) ? ... : Enumerable.Empty<String>();
.str.Length / chunkSize
kedouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
StringLength % 4 will always be 0
. JikaLinq
tidak mudah dipahami maka ada jawaban lain yang menggunakan loop dan hasil. Siapa pun bebas memilih solusi yang paling disukainya. Anda dapat memposting kode Anda sebagai jawaban dan orang-orang akan dengan senang hati memilihnya.Dalam kombinasi jawaban dove + Konstatin ...
Ini akan bekerja untuk semua string yang dapat dipecah menjadi sejumlah besar potongan, dan akan melemparkan pengecualian.
Jika Anda ingin mendukung string dengan panjang apa pun, Anda dapat menggunakan kode berikut:
Namun, OP secara eksplisit menyatakan dia tidak membutuhkan ini; itu agak lebih panjang dan sulit dibaca, sedikit lebih lambat. Dalam semangat KISS dan YAGNI, saya akan memilih opsi pertama: itu mungkin implementasi yang seefisien mungkin, dan sangat singkat, mudah dibaca, dan, yang penting, melempar pengecualian untuk input yang tidak sesuai.
sumber
Kenapa tidak loop? Inilah sesuatu yang akan melakukannya dengan cukup baik:
Saya tidak tahu bagaimana Anda akan berurusan dengan kasus di mana string bukan faktor 4, tetapi tidak mengatakan Anda ide tidak mungkin, hanya bertanya-tanya motivasi untuk itu jika sederhana untuk loop melakukannya dengan sangat baik? Jelas di atas bisa dibersihkan dan bahkan dimasukkan sebagai metode perpanjangan.
Atau seperti yang disebutkan dalam komentar, Anda tahu itu / 4 lalu
sumber
int chunkSize = 4
keluar dari loop. Itu hanya akan dimodifikasi pada pass terakhir.i += chunkSize
sebagai gantinya.str.Length
keluar dari loop dan ke dalam variabel lokal. Pengoptimal C # mungkin dapat inline panjang array, tapi saya pikir kode seperti yang tertulis akan melakukan pemanggilan metode pada setiap loop, yang tidak efisien, karena ukuranstr
tidak pernah berubah.Menggunakan ekspresi reguler dan Linq :
Saya menemukan ini lebih mudah dibaca, tetapi itu hanya pendapat pribadi. Ini juga bisa menjadi satu-baris:).
sumber
\d
kelas karakter dengan a.
dan untuk menentukanRegexOptions.Singleline
.Ini didasarkan pada solusi @dove tetapi diimplementasikan sebagai metode ekstensi.
Manfaat:
Kode
Pemakaian
Tes unit dihapus karena singkatnya (lihat revisi sebelumnya )
sumber
if (str.Length == 0) yield return String.Empty; else { for... }
IEnumerable
array, terutama tidak secara implisit.Chunkify
.. Itu bukan milik saya, saya tidak ingat di mana saya melihat nama itu, tetapi rasanya sangat menyenangkan bagi sayaBagaimana ini untuk satu-liner?
Dengan regex ini tidak masalah jika potongan terakhir kurang dari empat karakter, karena hanya pernah melihat karakter di belakangnya.
Saya yakin ini bukan solusi yang paling efisien, tetapi saya harus membuangnya di sana.
sumber
target.Lenght % ChunckSize == 0
itu mengembalikan baris kosong tambahan misalnyaList<string> result = new List<string>(Regex.Split("fooo", @"(?<=\G.{4})", RegexOptions.Singleline));
Itu tidak cantik dan tidak cepat, tetapi bekerja, ini satu-liner dan itu LINQy:
sumber
ToCharArray
tidak perlu karenastring
ituIEnumerable<char>
.Baru-baru ini saya harus menulis sesuatu yang menyelesaikan ini di tempat kerja, jadi saya pikir saya akan memposting solusi saya untuk masalah ini. Sebagai bonus tambahan, fungsionalitas dari solusi ini menyediakan cara untuk membagi string ke arah yang berlawanan dan itu benar menangani karakter unicode seperti yang disebutkan sebelumnya oleh Marvin Pinto di atas. Jadi begini:
Juga, di sini adalah tautan gambar ke hasil menjalankan kode ini: http://i.imgur.com/16Iih.png
sumber
{str.ToString()}
di akhir pernyataan IF pertama Anda. Apakah Anda yakin tidak bermaksud jahatstr.String
? Saya punya masalah dengan kode di atas, membuat perubahan itu, dan semuanya berfungsi.Ini harus jauh lebih cepat dan lebih efisien daripada menggunakan LINQ atau pendekatan lain yang digunakan di sini.
sumber
sumber
Anda dapat menggunakan morelinq oleh Jon Skeet. Gunakan Batch seperti:
Ini akan mengembalikan 4 potongan untuk string
"1111222233334444"
. Jika panjang string kurang dari atau sama dengan ukuran chunkBatch
akan mengembalikan string sebagai satu-satunya elemenIEnumerable<string>
Untuk output:
dan itu akan memberi:
sumber
dan pendekatan lain:
sumber
Enam tahun kemudian o_O
Hanya karena
atau
AFAIK semua kasus tepi ditangani.
sumber
Sederhana dan pendek:
sumber
.
?Itu benar menangani panjang string input tidak dapat dibagi oleh chunkSize.
Harap dicatat bahwa kode tambahan mungkin diperlukan untuk menangani kasus tepi dengan anggun (null atau string input kosong, chunkSize == 0).
sumber
Tip penting jika string yang sedang dipotong perlu untuk mendukung semua karakter Unicode.
Jika string ini untuk mendukung karakter internasional seperti
𠀋
, maka pisahkan string menggunakan kelas System.Globalization.StringInfo. Menggunakan StringInfo, Anda dapat membagi string berdasarkan jumlah elemen teks.String di atas memiliki Panjang 2, karena
String.Length
properti mengembalikan jumlah objek Char dalam contoh ini, bukan jumlah karakter Unicode.sumber
Jawaban Terbaik, Termudah dan Umum :).
sumber
Substring
overload yang tidak memerlukan parameter panjangoriginalString.Substring(i)
. Anda juga bisa menggunakannya>
sebagai ganti>=
cek Anda.Secara pribadi saya lebih suka solusi saya :-)
Ini menangani:
Ini diimplementasikan sebagai metode ekstensi, dan menghitung jumlah potongan yang akan dihasilkan sebelumnya. Ini memeriksa potongan terakhir karena jika panjang teks tidak banyak itu perlu lebih pendek. Bersih, pendek, mudah dimengerti ... dan berfungsi!
sumber
sumber
Saya pikir ini adalah jawaban langsung:
Dan itu mencakup kasus tepi.
sumber
Saya tahu pertanyaan sudah berumur bertahun-tahun, tetapi ini adalah implementasi Rx. Ini menangani
length % chunkSize != 0
masalah di luar kotak:sumber
Saya sedikit membangun solusi João. Apa yang saya lakukan secara berbeda adalah dalam metode saya, Anda benar-benar dapat menentukan apakah Anda ingin mengembalikan array dengan karakter yang tersisa atau apakah Anda ingin memotongnya jika karakter akhir tidak cocok dengan panjang chunk yang diperlukan, saya pikir itu cukup fleksibel dan kode cukup mudah:
sumber
sumber
Berubah sedikit untuk mengembalikan bagian yang ukurannya tidak sama dengan chunkSize
sumber
List
untukIEnumerable
; semua yang dilakukan adalah menyembunyikan fungsi khusus Daftar yang mungkin ingin Anda gunakan. Tidak ada kerugian apa pun untuk hanya mengembalikanList
.Saya tidak ingat siapa yang memberi saya ini, tetapi itu bekerja dengan baik. Saya mempercepat menguji sejumlah cara untuk memecah tipe Enumerable ke dalam kelompok. Penggunaannya akan seperti ini ...
Kode ekstensi akan terlihat seperti ini ...
sumber
sumber
i += offSet
kefor
ekspresi Anda .Modified (sekarang menerima setiap non nol
string
dan setiap positifchunkSize
) Konstantin Spirin 's solusi:Tes:
sumber
demo
sumber
Berdasarkan jawaban poster lainnya, bersama dengan beberapa contoh penggunaan:
sumber
Menggunakan ekstensi Buffer dari perpustakaan IX
sumber