एक निश्चित आकार के टुकड़े में एक स्ट्रिंग को विभाजित करना


218

मान लीजिए कि मेरे पास एक स्ट्रिंग थी:

string str = "1111222233334444"; 

मैं इस स्ट्रिंग को किसी आकार के टुकड़ों में कैसे तोड़ सकता हूं?

उदाहरण के लिए, इसे 4 के आकार में तोड़ना तार को लौटाएगा:

"1111"
"2222"
"3333"
"4444"

18
LINQ या regexes का उपयोग क्यों करें जब C # का मानक स्ट्रिंग हेरफेर फ़ंक्शन कम प्रयास और अधिक गति के साथ ऐसा कर सकता है? इसके अलावा, यदि स्ट्रिंग लम्बाई में विषम संख्या में वर्ण है तो क्या होगा?
इयान केम्प

7
"मैं छोरों से बचना चाहूंगा" - क्यों?
मिच गेहूं

12
एक साधारण लूप का उपयोग करना निश्चित रूप से सबसे अच्छा प्रदर्शन देता है।
गुफ़ा

4
nichesoftware.co.nz/blog/200909/linq-vs-loop-performance एक सरणी पर लाइनक और वास्तविक लूपिंग के बीच एक बहुत अच्छी तुलना है। मुझे संदेह है कि आप कभी भी मैन्युअल रूप से लिखे गए कोड की तुलना में तेजी से लिनक पाएंगे, क्योंकि यह रन-टाइम प्रतिनिधियों को कॉल करता रहता है जो दूर अनुकूलन के लिए कठिन हैं। Linq अधिक मज़ा है हालांकि :)
Blindy

2
चाहे आप LINQ या regexes का उपयोग कर रहे हों, लूप अभी भी है।
एंटोन टायखी

जवाबों:


247
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, आदि) से निपटने के लिए अतिरिक्त कोड की आवश्यकता हो सकती है । मूल प्रश्न इन धार मामलों के लिए कोई आवश्यकताएं निर्दिष्ट नहीं करता है और वास्तविक जीवन में आवश्यकताएं भिन्न हो सकती हैं, इसलिए वे इस उत्तर के दायरे से बाहर हैं।


3
@ हैरी गुड कैच! इसे प्रतिस्थापन के काउंट पैरामीटर पर ड्रॉप-इन टर्नरी एक्सप्रेशन के साथ रीमेड किया जा सकता है। की तरह कुछ: (i * chunkSize + chunkSize <= str.Length) ? chunkSize : str.Length - i * chunkSize। एक अतिरिक्त समस्या यह है कि यह फ़ंक्शन अशक्त होने के लिए जिम्मेदार नहीं है। यह पूरी वापसी विवरण को एक और टर्नरी अभिव्यक्ति में लपेटकर तय किया जा सकता है (str != null) ? ... : Enumerable.Empty<String>();:।
ड्रू स्पिक जूल

7
यह करीब था, लेकिन पिछले 30 upvoters के विपरीत, मैं से रेंज के पाश संख्या सीमा बदलना पड़ा str.Length / chunkSizeकरने के लिएdouble length = str.Length; double size = chunkSize; int count = (int)Math.Ceiling(length/size); return Enumerable.Range(0, count)...
अंतराल

4
@KonstantinSpirin अगर कोड काम करता है तो मैं सहमत हूं। यह केवल उस मामले को संभालता है जहां एक स्ट्रिंग कई प्रकार की चंकसाइज़ होती है, बाकी स्ट्रिंग खो जाती है। कृपया अमेंड करें। यह भी ध्यान रखें कि LINQ और यह जादू किसी को समझने में उतना आसान नहीं है जो इस समस्या के समाधान को देखना चाहता है। एक व्यक्ति को अब समझना चाहिए कि Enumerable.Range () और .Select () फ़ंक्शन क्या करते हैं। मैं यह तर्क नहीं दूंगा कि आपको C # /। NET कोड लिखने के लिए इसकी समझ होनी चाहिए क्योंकि ये कार्य कई वर्षों से BCL में हैं।
कोडमोनकीकिंग

6
विषय स्टार्टर ने टिप्पणियों में कहा कि StringLength % 4 will always be 0। यदि Linqसमझना आसान नहीं है तो ऐसे अन्य उत्तर हैं जो लूप और पैदावार का उपयोग करते हैं। कोई भी उस समाधान को चुनने के लिए स्वतंत्र है जिसे वह सबसे अच्छा पसंद करता है। आप अपने कोड को एक उत्तर के रूप में पोस्ट कर सकते हैं और लोग खुशी से इसके लिए मतदान करेंगे।
कॉन्स्टेंटिन स्पिरिन

3
Enumerable.Range (0, (str.Length + chunkSize - 1) / chunkSize)। चयन करें (i => str.Substring (i * chunkSize, Math.Min (str.Length - * chunkSize, chunkSize)))
Sten पेट्रोव

135

कबूतर + कॉन्स्टैटिन के जवाब के संयोजन में ...

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));
}

हालांकि, ओपी ने स्पष्ट रूप से कहा कि उसे इसकी आवश्यकता नहीं है; यह थोड़ा लंबा और पढ़ने में कठिन है, थोड़ा धीमा। चुंबन और YAGNI की भावना में, मैं पहले विकल्प के साथ जाना चाहते हैं: यह शायद सबसे कुशल कार्यान्वयन संभव है, और यह बहुत ही कम, पठनीय है, और, महत्वपूर्ण बात, इनपुट गैर-अनुरूपक के लिए एक अपवाद फेंकता है।


4
एक लायक एक नोड। थोड़े सिर पर नाखून मारता है। वह सक्सेना सिंटैक्स की तलाश में है और आप (शायद) बेहतर प्रदर्शन भी दे रहे हैं।
कबूतर

7
और अगर आप इसे "स्टैटिक ... चंक (यह स्ट्रिंग str, int chunkSize) {" बनाते हैं, तो आपके पास इसमें एक और "नया" C # -Feature भी होगा। फिर आप "1111222233334444" लिख सकते हैं। घन (4)।
मार्टिनस्टेटनर

1
@MartinStettner: यह निश्चित रूप से एक अच्छा विचार है अगर यह एक सामान्य ऑपरेशन है।
Eamon Nerbonne

आपको केवल बाद वाला कोड शामिल करना चाहिए। पूर्व के लिए आवश्यक है कि आप स्ट्रिंग के लिए समझने और परीक्षण करने के लिए उपयोग करने से पहले कई चंक आकार का हो, या यह समझ लें कि यह स्ट्रिंग के शेष को वापस नहीं करेगा।
कोडमोनकीकिंग

ओपी का सवाल यह स्पष्ट नहीं करता है कि क्या उसे उस कार्यक्षमता की आवश्यकता है। पहला समाधान सरल, तेज और मज़बूती से एक अपवाद के साथ विफल होता है अगर स्ट्रिंग को निर्दिष्ट चंक आकार में समान रूप से विभाजित नहीं किया जा सकता है। मैं मानता हूं कि "गलत" परिणाम वापस करना बुरा होगा, लेकिन यह नहीं कि यह क्या करता है - यह सिर्फ एक अपवाद फेंकता है, इसलिए यदि आप सीमा के साथ रह सकते हैं तो मैं इसका उपयोग करना ठीक होगा।
ईमोन नर्बोने

56

लूप क्यों नहीं? यहाँ कुछ ऐसा है जो इसे बहुत अच्छा करेगा:

        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));} 

1
आप int chunkSize = 4लूप के बाहर खींच सकते हैं । इसे केवल अंतिम पास पर ही संशोधित किया जाएगा।
जॉन फेमिनाला

एक सरल और प्रभावी समाधान के लिए +1 - यह है कि मैंने इसे कैसे किया होगा, हालांकि मैंने i += chunkSizeइसके बजाय उपयोग किया होगा।
इयान केम्प

संभवतः एक मामूली वक्रोक्ति, लेकिन आपको संभवतः str.Lengthलूप से बाहर और एक स्थानीय चर में भी खींचना चाहिए । C # ऑप्टिमाइज़र इनलाइन सरणी लंबाई में सक्षम हो सकता है, लेकिन मुझे लगता है कि जैसा कोड लिखा गया है वह हर लूप पर एक विधि कॉल करेगा, जो कि कुशल नहीं है, क्योंकि आकार strकभी नहीं बदलता है।
डैनियल प्राइडेन

@ डैनियल, अपना आइडिया वहां डालिए। हालांकि मुझे यकीन नहीं है कि यह रनटाइम पर गणना नहीं की जाएगी, लेकिन यह एक और सवाल है;)
कबूतर

@ डैनियल इस पर वापस आ रहा है, यकीन है कि यह अनुकूलन संकलक द्वारा निकाला जाएगा।
कबूतर

41

नियमित अभिव्यक्ति और Linq का उपयोग करना :

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

मुझे यह अधिक पठनीय लगता है, लेकिन यह सिर्फ एक व्यक्तिगत राय है। यह वन-लाइनर भी हो सकता है:)।


7
पैटर्न को @ "\ d {1,4}" में बदलें और यह किसी भी स्ट्रिंग लंबाई के लिए काम करता है। :)
गुफ़ा

3
+1 हालांकि यह अन्य समाधानों की तुलना में धीमा है, यह निश्चित रूप से बहुत पठनीय है। यह मेरे लिए स्पष्ट नहीं है कि क्या ओपी को अंकों या मनमाने पात्रों की आवश्यकता है; संभवतः \dवर्ण वर्ग को ए .और निर्दिष्ट करने के लिए प्रतिस्थापित करना बुद्धिमानी होगी RegexOptions.Singleline
Eamon Nerbonne

2
या बस Regex.Matches (s, @ "\ d {1,4}") का चयन करें (m => m.Value) .ToList (); मुझे इस वैकल्पिक सिंटैक्स की बात कभी नहीं मिली जो केवल उन तरीकों को मानने के लिए कार्य करता है जो हम विस्तार विधियों का उपयोग कर रहे हैं।
द डग

38

यह @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... }
Nyerguds

मेरा मतलब है, यह है कि सामान्य String.Split खाली तारों को कैसे संभालता है; यह एक खाली स्ट्रिंग प्रविष्टि देता है।
Nyerguds

साइड नोट: आपका उपयोग उदाहरण गलत है। आप केवल IEnumerableसरणी के लिए नहीं डाल सकते , विशेष रूप से निहित नहीं।
Nyerguds

मुझे व्यक्तिगत रूप से उस पद्धति को कॉल करना पसंद है Chunkify.. यह मेरा नहीं है, मुझे याद नहीं है कि मैंने उस नाम को कहां देखा है, लेकिन यह मुझे बहुत अच्छा लगा
quetzalcoatl

20

एक-लाइनर के लिए यह कैसा है?

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));
fubo

9

यह सुंदर नहीं है और यह तेज़ नहीं है, लेकिन यह काम करता है, यह एक-लाइनर है और यह 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();

क्या यह गारंटी है कि GroupBy तत्वों के आदेश को संरक्षित करता है?
कॉन्स्टेंटिन स्पिरिन

ToCharArrayके बाद से अनावश्यक है stringहै IEnumerable<char>
जुहेर

8

मुझे हाल ही में कुछ लिखना था जो काम पर इसे पूरा करता है, इसलिए मैंने सोचा कि मैं इस समस्या का समाधान निकालूंगा। एक अतिरिक्त बोनस के रूप में, इस समाधान की कार्यक्षमता विपरीत दिशा में स्ट्रिंग को विभाजित करने का एक तरीका प्रदान करती है और यह ठीक से यूनिकोड वर्णों को संभालती है जैसा कि ऊपर बताए गए मार्विन पिंटो ने पहले उल्लेख किया था। तो, यहाँ यह है:

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


1
मैंने इस कोड के साथ एक समस्या देखी। आपके पास {str.ToString()}अपना पहला IF स्टेटमेंट है। क्या आप सुनिश्चित हैं कि आपका मतलब नहीं था str.String? मुझे ऊपर दिए गए कोड के साथ एक समस्या थी, उस बदलाव को बनाया, और सब कुछ काम किया।
gunr2171

@ gunr2171 ऐसा लगता है कि अगर str == null है, तो वह लाइन NullReferenceException भी देगी।
जॉन ज़ब्रोस्की

5

यह लाइनक्यू या यहां उपयोग किए जाने वाले अन्य तरीकों की तुलना में बहुत तेज और अधिक कुशल होना चाहिए।

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);
}

ऐसा लगता है कि यह जल्दी जाँच करता है, लेकिन ऐसा नहीं है। जब तक आप enumerable की गणना शुरू नहीं करते तब तक आपको एक त्रुटि नहीं मिलती है। आपको अपने कार्य को दो भागों में विभाजित करने की आवश्यकता है, जहां पहला भाग तर्क की जाँच करता है, और फिर दूसरे, निजी भाग के परिणामों की गणना करता है।
एरिक

4
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;
}

4

जॉन स्कीट द्वारा आप मोरेलिनक का उपयोग कर सकते हैं । जैसे बैच का उपयोग करें :

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

MoreLINQ के लेखकों में मैं जोनाथन स्कीट को देखता हूं , लेकिन कोई जॉन स्कीट नहीं । तो तुम क्या मतलब था जॉन स्कीट, या क्या? ;-)
SAN-)ошƒаӽ

3
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));
    }
}

3

छह साल बाद ओ_ओ

सिर्फ इसलिए कि

    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

"इनपुट एक खाली स्ट्रिंग" किनारे के मामले के बारे में क्या है? मुझे उम्मीद है कि, स्प्लिट की तरह ही, IEnumerable को एक सिंगल-स्ट्रिंग युक्त एंट्री के साथ वापस करने के लिए।
Nyerguds

3

सरल और संक्षिप्त:

// 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);

उपयोग क्यों नहीं .?
मार्सज़

3
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) को सुशोभित करने के लिए अतिरिक्त कोड की आवश्यकता हो सकती है।


2

एक महत्वपूर्ण टिप अगर कड़ा हो रहा है जो सभी यूनिकोड वर्णों का समर्थन करने की आवश्यकता है।

यदि स्ट्रिंग को अंतरराष्ट्रीय वर्णों का समर्थन करना है 𠀋, तो System.Globalization.StringInfo वर्ग का उपयोग करके स्ट्रिंग को विभाजित करें। StringInfo का उपयोग करके, आप पाठ तत्वों की संख्या के आधार पर स्ट्रिंग को विभाजित कर सकते हैं।

string internationalString = '𠀋';

उपरोक्त स्ट्रिंग की लंबाई 2 है, क्योंकि String.Lengthसंपत्ति इस उदाहरण में चार वस्तुओं की संख्या लौटाती है, यूनिकोड वर्णों की संख्या नहीं।


2

सबसे अच्छा, सबसे आसान और सामान्य उत्तर :)।

    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)। इसके अलावा आप अपने चेक के >बजाय उपयोग कर सकते हैं >=
राहिल हिलन

@RacilHilan मैं आपके सुझावों के साथ कोड परिवर्तन का परीक्षण करूंगा और उत्तर को अपडेट करूंगा। मुझे खुशी है कि इतनी अच्छी प्रतिष्ठा वाले किसी व्यक्ति को मेरे कोड की समीक्षा करने का समय मिला। :) धन्यवाद, संदीप
संदीप कुशवाह

2

व्यक्तिगत रूप से मैं अपना समाधान पसंद करता हूं :-)

यह संभालता है:

  • स्ट्रिंग की लंबाई जो कि चंक साइज के कई हैं।
  • स्ट्रिंग की लंबाई जो कि चंक आकार के एक से अधिक नहीं हैं।
  • स्ट्रिंग की लंबाई जो चंक के आकार से छोटी होती है।
  • रिक्त और खाली तार (एक अपवाद फेंकता है)।
  • 1 से छोटा आकार छोटा (एक अपवाद फेंकता है)।

यह एक विस्तार विधि के रूप में लागू किया जाता है, और यह गणना करता है कि विखंडू की संख्या पहले से उत्पन्न होने वाली है। यह अंतिम चंक की जांच करता है क्योंकि यदि पाठ की लंबाई एक से अधिक नहीं है तो इसे छोटा होना चाहिए। साफ, छोटा, समझने में आसान ... और काम करता है!

    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;
    }

2
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;
}

1
मुझे यह उत्तर बहुत पसंद है, लेकिन शायद आपको असाधारण मामलों के लिए अपवाद के रूप में (i + 1) * chunk> = input.Length का उपयोग करने की कोशिश करनी चाहिए।
nelsontruran

2

मुझे लगता है कि यह एक सीधा आगे का जवाब है:

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);
        }
    }

और यह बढ़त के मामलों को कवर करता है।


2

मुझे पता है कि प्रश्न वर्षों पुराना है, लेकिन यहां एक आरएक्स कार्यान्वयन है। यह 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();
        }

1

मैंने जोआओ के समाधान पर थोड़ा निर्माण किया है। जो मैंने अलग तरीके से किया है वह मेरी विधि में है आप वास्तव में निर्दिष्ट कर सकते हैं कि क्या आप शेष वर्णों के साथ सरणी वापस करना चाहते हैं या क्या आप उन्हें समाप्त करना चाहते हैं यदि अंतिम वर्ण आपकी आवश्यक लंबाई से मेल नहीं खाते हैं, तो मुझे लगता है कि यह बहुत लचीला है और कोड काफी सीधे आगे है:

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;
        }     
    }
}

1
    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;
    }

आप, एह, MaxLength पैरामीटर को भूल गए।
Nyerguds

1

उन हिस्सों को वापस करने के लिए थोड़ा बदल दिया जिनका आकार chunkSize के बराबर नहीं है

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
Nyerguds

1

मुझे याद नहीं है कि किसने मुझे यह दिया, लेकिन यह बहुत अच्छा काम करता है। मैंने समूहों में असंख्य प्रकारों को तोड़ने के कई तरीकों का परीक्षण किया। उपयोग सिर्फ इस तरह होगा ...

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

1
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अभिव्यक्ति में बदल दें ।
जिमीलो जुए

1

संशोधित (अब यह किसी भी अशक्त stringऔर किसी भी सकारात्मक chunkSize) कॉन्स्टेंटिन स्पिरिन के समाधान को स्वीकार करता है :

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));

1
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;
}

डेमो


यह एक स्ट्रिंग के शेष (पोस्ट विभाजन) को रखता है यहां तक ​​कि यह "चंकलेन्थ" से छोटा है, धन्यवाद
जेसन लोकी स्मिथ

0

अन्य पोस्टरों के उत्तर के आधार पर, कुछ नमूने के साथ:

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();
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.