按字符串长度变量将String拆分为较小的字符串

时间:2023-01-29 21:41:57

I'd like to break apart a String by a certain length variable.
It needs to bounds check so as not explode when the last section of string is not as long as or longer than the length. Looking for the most succinct (yet understandable) version.

我想用特定的长度变量拆分String。它需要检查边界,以便在字符串的最后一部分不长于或长于字符串时不会爆炸。寻找最简洁(但可以理解)的版本。

Example:

例:

string x = "AAABBBCC";
string[] arr = x.SplitByLength(3);
// arr[0] -> "AAA";
// arr[1] -> "BBB";
// arr[2] -> "CC"

11 个解决方案

#1


62  

You need to use a loop:

你需要使用一个循环:

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    for (int index = 0; index < str.Length; index += maxLength) {
        yield return str.Substring(index, Math.Min(maxLength, str.Length - index));
    }
}

Alternative:

替代方案:

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    int index = 0;
    while(true) {
        if (index + maxLength >= str.Length) {
            yield return str.Substring(index);
            yield break;
        }
        yield return str.Substring(index, maxLength);
        index += maxLength;
    }
}

2nd alternative: (For those who can't stand while(true))

第二种选择:(对于那些不能忍受的人(真))

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    int index = 0;
    while(index + maxLength < str.Length) {
        yield return str.Substring(index, maxLength);
        index += maxLength;
    }

    yield return str.Substring(index);
}

#2


11  

Easy to understand version:

易于理解的版本:

string x = "AAABBBCC";
List<string> a = new List<string>();
for (int i = 0; i < x.Length; i += 3)
{
    if((i + 3) < x.Length)
        a.Add(x.Substring(i, 3));
    else
        a.Add(x.Substring(i));
}

Though preferably the 3 should be a nice const.

虽然最好3应该是一个很好的常量。

#3


6  

It's not particularly succinct, but I might use an extension method like this:

它不是特别简洁,但我可能会使用这样的扩展方法:

public static IEnumerable<string> SplitByLength(this string s, int length)
{
    for (int i = 0; i < s.Length; i += length)
    {
        if (i + length <= s.Length)
        {
            yield return s.Substring(i, length);
        }
        else
        {
            yield return s.Substring(i);
        }
    }
}

Note that I return an IEnumerable<string>, not an array. If you want to convert the result to an array, use ToArray:

请注意,我返回一个IEnumerable ,而不是一个数组。如果要将结果转换为数组,请使用ToArray:

string[] arr = x.SplitByLength(3).ToArray();

#4


4  

Here's what I'd do:

这是我要做的:

public static IEnumerable<string> EnumerateByLength(this string text, int length) {
    int index = 0;
    while (index < text.Length) {
        int charCount = Math.Min(length, text.Length - index);
        yield return text.Substring(index, charCount);
        index += length;
    }
}

This method would provide deferred execution (which doesn't really matter on an immutable class like string, but it's worth noting).

这种方法将提供延迟执行(这对于像字符串这样的不可变类并不重要,但值得注意)。

Then if you wanted a method to populate an array for you, you could have:

然后,如果您想要一个方法为您填充数组,您可以:

public static string[] SplitByLength(this string text, int length) {
    return text.EnumerateByLength(length).ToArray();
}

The reason I would go with the name EnumerateByLength rather then SplitByLength for the "core" method is that string.Split returns a string[], so in my mind there's precedence for methods whose names start with Split to return arrays.

我之所以使用名称EnumerateByLength而不是SplitByLength作为“核心”方法,是因为string.Split返回一个字符串[],所以在我看来,名称以Split开头的方法返回数组是优先的。

That's just me, though.

不过,那只是我。

#5


3  

My solution:

我的解决方案

public static string[] SplitToChunks(this string source, int maxLength)
{
    return source
        .Where((x, i) => i % maxLength == 0)
        .Select(
            (x, i) => new string(source
                .Skip(i * maxLength)
                .Take(maxLength)
                .ToArray()))
        .ToArray();
}

I actually rather use List<string> instead of string[].

我实际上更喜欢使用List 而不是string []。

#6


1  

Using Batch from MoreLinq, on .Net 4.0:

在.Net 4.0上使用MoreLinq中的批处理:

public static IEnumerable<string> SplitByLength(this string str, int length)
{
    return str.Batch(length, String.Concat);
}

On 3.5 Concat need an array, so we can use Concat with ToArray or, new String:

在3.5 Concat需要一个数组,所以我们可以使用Concat和ToArray,或者新的String:

public static IEnumerable<string> SplitByLength(this string str, int length)
{
    return str.Batch(length, chars => new String(chars.ToArray()));
}

It may be a bit unintuitive to look at a string as a collection of characters, so string manipulation might be proffered.

将字符串视为字符集合可能有点不直观,因此可能会提供字符串操作。

#7


1  

Yet another slight variant (classic but simple and pragmatic):

又一个轻微的变体(经典但简单而实用):

class Program
{
    static void Main(string[] args) {
        string msg = "AAABBBCC";

        string[] test = msg.SplitByLength(3);            
    }
}

public static class SplitStringByLength
{
    public static string[] SplitByLength(this string inputString, int segmentSize) {
        List<string> segments = new List<string>();

        int wholeSegmentCount = inputString.Length / segmentSize;

        int i;
        for (i = 0; i < wholeSegmentCount; i++) {
            segments.Add(inputString.Substring(i * segmentSize, segmentSize));
        }

        if (inputString.Length % segmentSize != 0) {
            segments.Add(inputString.Substring(i * segmentSize, inputString.Length - i * segmentSize));
        }

        return segments.ToArray();
    }
}

#8


1  

UPD: Using some Linq to make it actually succinct

UPD:使用一些Linq使它实际上简洁


static IEnumerable EnumerateByLength(string str, int len)
        {
            Match m = (new Regex(string.Format("^(.{{1,{0}}})*$", len))).Match(str);
            if (m.Groups.Count <= 1)
                return Empty;
            return (from Capture c in m.Groups[1].Captures select c.Value);
        }

Initial version:

初始版本:


        static string[] Empty = new string [] {};

        static string[] SplitByLength(string str, int len)
        {
            Regex r = new Regex(string.Format("^(.{{1,{0}}})*$",len));
            Match m = r.Match(str);
            if(m.Groups.Count <= 1)
                return Empty;

            string [] result = new string[m.Groups[1].Captures.Count];
            int ix = 0;
            foreach(Capture c in m.Groups[1].Captures)
            {
                result[ix++] = c.Value;
            }
            return result;
        }

#9


0  

    private string[] SplitByLength(string s, int d)
    {
        List<string> stringList = new List<string>();
        if (s.Length <= d) stringList.Add(s);
        else
        {
            int x = 0;
            for (; (x + d) < s.Length; x += d)
            {
                stringList.Add(s.Substring(x, d));
            }
            stringList.Add(s.Substring(x));
        }
        return stringList.ToArray();
    }

#10


0  

    private void button2_Click(object sender, EventArgs e)
    {
        string s = "AAABBBCCC";
        string[] a = SplitByLenght(s,3);
    }

    private string[] SplitByLenght(string s, int split)
    {
        //Like using List because I can just add to it 
        List<string> list = new List<string>();

                    // Integer Division
        int TimesThroughTheLoop = s.Length/split;


        for (int i = 0; i < TimesThroughTheLoop; i++)
        {
            list.Add(s.Substring(i * split, split));

        }

        // Pickup the end of the string
        if (TimesThroughTheLoop * split != s.Length)
        {
            list.Add(s.Substring(TimesThroughTheLoop * split));
        }

        return list.ToArray();
    }

#11


0  

I had the strange scenario where I had segmented a string, then rearranged the segments (i.e. reversed) before concatenating them, and then I later needed to reverse the segmentation. Here's an update to the accepted answer by @SLaks:

我有一个奇怪的场景,我已经分割了一个字符串,然后重新排列段(即反转),然后连接它们,然后我需要反转分段。以下是@SLaks接受的答案的更新:

    /// <summary>
    /// Split the given string into equally-sized segments (possibly with a 'remainder' if uneven division).  Optionally return the 'remainder' first.
    /// </summary>
    /// <param name="str">source string</param>
    /// <param name="maxLength">size of each segment (except the remainder, which will be less)</param>
    /// <param name="remainderFirst">if dividing <paramref name="str"/> into segments would result in a chunk smaller than <paramref name="maxLength"/> left at the end, instead take it from the beginning</param>
    /// <returns>list of segments within <paramref name="str"/></returns>
    /// <remarks>Original method at https://*.com/questions/3008718/split-string-into-smaller-strings-by-length-variable </remarks>
    private static IEnumerable<string> ToSegments(string str, int maxLength, bool remainderFirst = false) {
        // note: `maxLength == 0` would not only not make sense, but would result in an infinite loop
        if(maxLength < 1) throw new ArgumentOutOfRangeException("maxLength", maxLength, "Should be greater than 0");
        // correct for the infinite loop caused by a nonsensical request of `remainderFirst == true` and no remainder (`maxLength==1` or even division)
        if( remainderFirst && str.Length % maxLength == 0 ) remainderFirst = false;

        var index = 0;
        // note that we want to stop BEFORE we reach the end
        // because if it's exact we'll end up with an
        // empty segment
        while (index + maxLength < str.Length)
        {
            // do we want the 'final chunk' first or at the end?
            if( remainderFirst && index == 0 ) {
                // figure out remainder size
                var remainder = str.Length % maxLength;
                yield return str.Substring(index, remainder);

                index += remainder;
            }
            // normal stepthrough
            else {
                yield return str.Substring(index, maxLength);
                index += maxLength;
            }
        }

        yield return str.Substring(index);
    }//---  fn  ToSegments

(I also corrected a bug in the original while version resulting in empty segment if maxLength==1)

(我还更正了原始版本中的错误,如果maxLength == 1,则会导致空片段)

#1


62  

You need to use a loop:

你需要使用一个循环:

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    for (int index = 0; index < str.Length; index += maxLength) {
        yield return str.Substring(index, Math.Min(maxLength, str.Length - index));
    }
}

Alternative:

替代方案:

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    int index = 0;
    while(true) {
        if (index + maxLength >= str.Length) {
            yield return str.Substring(index);
            yield break;
        }
        yield return str.Substring(index, maxLength);
        index += maxLength;
    }
}

2nd alternative: (For those who can't stand while(true))

第二种选择:(对于那些不能忍受的人(真))

public static IEnumerable<string> SplitByLength(this string str, int maxLength) {
    int index = 0;
    while(index + maxLength < str.Length) {
        yield return str.Substring(index, maxLength);
        index += maxLength;
    }

    yield return str.Substring(index);
}

#2


11  

Easy to understand version:

易于理解的版本:

string x = "AAABBBCC";
List<string> a = new List<string>();
for (int i = 0; i < x.Length; i += 3)
{
    if((i + 3) < x.Length)
        a.Add(x.Substring(i, 3));
    else
        a.Add(x.Substring(i));
}

Though preferably the 3 should be a nice const.

虽然最好3应该是一个很好的常量。

#3


6  

It's not particularly succinct, but I might use an extension method like this:

它不是特别简洁,但我可能会使用这样的扩展方法:

public static IEnumerable<string> SplitByLength(this string s, int length)
{
    for (int i = 0; i < s.Length; i += length)
    {
        if (i + length <= s.Length)
        {
            yield return s.Substring(i, length);
        }
        else
        {
            yield return s.Substring(i);
        }
    }
}

Note that I return an IEnumerable<string>, not an array. If you want to convert the result to an array, use ToArray:

请注意,我返回一个IEnumerable ,而不是一个数组。如果要将结果转换为数组,请使用ToArray:

string[] arr = x.SplitByLength(3).ToArray();

#4


4  

Here's what I'd do:

这是我要做的:

public static IEnumerable<string> EnumerateByLength(this string text, int length) {
    int index = 0;
    while (index < text.Length) {
        int charCount = Math.Min(length, text.Length - index);
        yield return text.Substring(index, charCount);
        index += length;
    }
}

This method would provide deferred execution (which doesn't really matter on an immutable class like string, but it's worth noting).

这种方法将提供延迟执行(这对于像字符串这样的不可变类并不重要,但值得注意)。

Then if you wanted a method to populate an array for you, you could have:

然后,如果您想要一个方法为您填充数组,您可以:

public static string[] SplitByLength(this string text, int length) {
    return text.EnumerateByLength(length).ToArray();
}

The reason I would go with the name EnumerateByLength rather then SplitByLength for the "core" method is that string.Split returns a string[], so in my mind there's precedence for methods whose names start with Split to return arrays.

我之所以使用名称EnumerateByLength而不是SplitByLength作为“核心”方法,是因为string.Split返回一个字符串[],所以在我看来,名称以Split开头的方法返回数组是优先的。

That's just me, though.

不过,那只是我。

#5


3  

My solution:

我的解决方案

public static string[] SplitToChunks(this string source, int maxLength)
{
    return source
        .Where((x, i) => i % maxLength == 0)
        .Select(
            (x, i) => new string(source
                .Skip(i * maxLength)
                .Take(maxLength)
                .ToArray()))
        .ToArray();
}

I actually rather use List<string> instead of string[].

我实际上更喜欢使用List 而不是string []。

#6


1  

Using Batch from MoreLinq, on .Net 4.0:

在.Net 4.0上使用MoreLinq中的批处理:

public static IEnumerable<string> SplitByLength(this string str, int length)
{
    return str.Batch(length, String.Concat);
}

On 3.5 Concat need an array, so we can use Concat with ToArray or, new String:

在3.5 Concat需要一个数组,所以我们可以使用Concat和ToArray,或者新的String:

public static IEnumerable<string> SplitByLength(this string str, int length)
{
    return str.Batch(length, chars => new String(chars.ToArray()));
}

It may be a bit unintuitive to look at a string as a collection of characters, so string manipulation might be proffered.

将字符串视为字符集合可能有点不直观,因此可能会提供字符串操作。

#7


1  

Yet another slight variant (classic but simple and pragmatic):

又一个轻微的变体(经典但简单而实用):

class Program
{
    static void Main(string[] args) {
        string msg = "AAABBBCC";

        string[] test = msg.SplitByLength(3);            
    }
}

public static class SplitStringByLength
{
    public static string[] SplitByLength(this string inputString, int segmentSize) {
        List<string> segments = new List<string>();

        int wholeSegmentCount = inputString.Length / segmentSize;

        int i;
        for (i = 0; i < wholeSegmentCount; i++) {
            segments.Add(inputString.Substring(i * segmentSize, segmentSize));
        }

        if (inputString.Length % segmentSize != 0) {
            segments.Add(inputString.Substring(i * segmentSize, inputString.Length - i * segmentSize));
        }

        return segments.ToArray();
    }
}

#8


1  

UPD: Using some Linq to make it actually succinct

UPD:使用一些Linq使它实际上简洁


static IEnumerable EnumerateByLength(string str, int len)
        {
            Match m = (new Regex(string.Format("^(.{{1,{0}}})*$", len))).Match(str);
            if (m.Groups.Count <= 1)
                return Empty;
            return (from Capture c in m.Groups[1].Captures select c.Value);
        }

Initial version:

初始版本:


        static string[] Empty = new string [] {};

        static string[] SplitByLength(string str, int len)
        {
            Regex r = new Regex(string.Format("^(.{{1,{0}}})*$",len));
            Match m = r.Match(str);
            if(m.Groups.Count <= 1)
                return Empty;

            string [] result = new string[m.Groups[1].Captures.Count];
            int ix = 0;
            foreach(Capture c in m.Groups[1].Captures)
            {
                result[ix++] = c.Value;
            }
            return result;
        }

#9


0  

    private string[] SplitByLength(string s, int d)
    {
        List<string> stringList = new List<string>();
        if (s.Length <= d) stringList.Add(s);
        else
        {
            int x = 0;
            for (; (x + d) < s.Length; x += d)
            {
                stringList.Add(s.Substring(x, d));
            }
            stringList.Add(s.Substring(x));
        }
        return stringList.ToArray();
    }

#10


0  

    private void button2_Click(object sender, EventArgs e)
    {
        string s = "AAABBBCCC";
        string[] a = SplitByLenght(s,3);
    }

    private string[] SplitByLenght(string s, int split)
    {
        //Like using List because I can just add to it 
        List<string> list = new List<string>();

                    // Integer Division
        int TimesThroughTheLoop = s.Length/split;


        for (int i = 0; i < TimesThroughTheLoop; i++)
        {
            list.Add(s.Substring(i * split, split));

        }

        // Pickup the end of the string
        if (TimesThroughTheLoop * split != s.Length)
        {
            list.Add(s.Substring(TimesThroughTheLoop * split));
        }

        return list.ToArray();
    }

#11


0  

I had the strange scenario where I had segmented a string, then rearranged the segments (i.e. reversed) before concatenating them, and then I later needed to reverse the segmentation. Here's an update to the accepted answer by @SLaks:

我有一个奇怪的场景,我已经分割了一个字符串,然后重新排列段(即反转),然后连接它们,然后我需要反转分段。以下是@SLaks接受的答案的更新:

    /// <summary>
    /// Split the given string into equally-sized segments (possibly with a 'remainder' if uneven division).  Optionally return the 'remainder' first.
    /// </summary>
    /// <param name="str">source string</param>
    /// <param name="maxLength">size of each segment (except the remainder, which will be less)</param>
    /// <param name="remainderFirst">if dividing <paramref name="str"/> into segments would result in a chunk smaller than <paramref name="maxLength"/> left at the end, instead take it from the beginning</param>
    /// <returns>list of segments within <paramref name="str"/></returns>
    /// <remarks>Original method at https://*.com/questions/3008718/split-string-into-smaller-strings-by-length-variable </remarks>
    private static IEnumerable<string> ToSegments(string str, int maxLength, bool remainderFirst = false) {
        // note: `maxLength == 0` would not only not make sense, but would result in an infinite loop
        if(maxLength < 1) throw new ArgumentOutOfRangeException("maxLength", maxLength, "Should be greater than 0");
        // correct for the infinite loop caused by a nonsensical request of `remainderFirst == true` and no remainder (`maxLength==1` or even division)
        if( remainderFirst && str.Length % maxLength == 0 ) remainderFirst = false;

        var index = 0;
        // note that we want to stop BEFORE we reach the end
        // because if it's exact we'll end up with an
        // empty segment
        while (index + maxLength < str.Length)
        {
            // do we want the 'final chunk' first or at the end?
            if( remainderFirst && index == 0 ) {
                // figure out remainder size
                var remainder = str.Length % maxLength;
                yield return str.Substring(index, remainder);

                index += remainder;
            }
            // normal stepthrough
            else {
                yield return str.Substring(index, maxLength);
                index += maxLength;
            }
        }

        yield return str.Substring(index);
    }//---  fn  ToSegments

(I also corrected a bug in the original while version resulting in empty segment if maxLength==1)

(我还更正了原始版本中的错误,如果maxLength == 1,则会导致空片段)