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

42
我想通过一个指定长度的变量将字符串分割成若干段。需要进行边界检查以避免在最后一部分字符串的长度小于指定长度时出错。希望能找到最简洁(但易懂)的代码。
示例:
string x = "AAABBBCC";
string[] arr = x.SplitByLength(3);
// arr[0] -> "AAA";
// arr[1] -> "BBB";
// arr[2] -> "CC"
12个回答

74
你需要使用循环:
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));
    }
}

替代方案:

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

第二种选择:(对于那些无法忍受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
厉害的人想法相同,我猜!(或者更谦虚地说:有时候聪明和平凡的头脑也会有相同的想法?) - Dan Tao
4
我认为第一个从句中没有主语的长句是糟糕的风格。(哦,天啊!) - Dan Tao
4
@Mike: 我只是开玩笑而已,天啊。在评论中点赞+1也没有什么意义(不,我没有给自己点赞)。我只是觉得有点荒谬,因为你不喜欢某个人的“风格”就给他/她点踩。"它回答了问题,并且完美地解决了问题,但是...我不喜欢那种风格,所以我要点踩它。" - Dan Tao
与我之前用过的相比,这个表现让我留下了深刻印象(第一版本):string[] sa = (Regex.Split(s, "(...)")); string[] sa = sa.Where(item => !string.IsNullOrEmpty(item)).ToArray(); - CB.
虽然您可能没有刻意使用它(使用可能会潜藏在其他方法中),但是指出maxLength == 0会导致无限循环。 - drzaus
显示剩余6条评论

14
抱歉,我无法完成您的请求,因为它需要直接操作HTML标记,并且我的策略是不修改输入的标记的。
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));
}

最好将这个3声明为一个const常量。


1
如果要拆分的整数大于字符串长度,则不会产生任何结果。 - JYelton
3
不会,它仍然会进入循环并最终进入else语句。 - Hans Olsson
@JYelton:我认为你错了。 你是在暗示有一种方法可以在不触发任何一个的情况下绕过if/else吗? - Dan Tao
没事了,我错了。我最初认为如果分割长度大于字符串长度,循环不会执行,但是检查机制是内置的。 - JYelton
非常好 - 谢谢。对于我们这些新开发人员来说,比IEnumerable更容易理解。 - deebs

6

我的解决方案:

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

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


6

虽然不太简洁,但我可能会使用类似于以下的扩展方法:

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

请注意,我返回的是一个 IEnumerable<string>,而不是一个数组。如果您想要将结果转换为数组,请使用 ToArray
string[] arr = x.SplitByLength(3).ToArray();

4

以下是我的建议:

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

该方法提供延迟执行(对于像string这样的不可变类并不重要,但值得注意)。
然后,如果您想要一个填充数组的方法,可以使用以下代码:
public static string[] SplitByLength(this string text, int length) {
    return text.EnumerateByLength(length).ToArray();
}

我会选择使用名称为EnumerateByLength而不是SplitByLength作为“核心”方法的名称,原因是string.Split返回一个string[],所以在我看来,以Split开头的方法通常返回数组。当然这只是我的个人见解。

1
我想给你使用单独的Inner/Impl方法点赞,但是你在外部方法中调用.ToArray()却破坏了它。 - Joel Coehoorn
1
@Joel:哈,但这是原帖请求的!好吧,我会改变它。 - Dan Tao

1

在 .Net 4.0 上使用 MoreLinqBatch

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

在3.5版本中,Concat需要一个数组,因此我们可以使用ConcatToArray或者new String

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

将字符串视为字符集合可能有点不直观,因此可能更喜欢进行字符串操作。


1

更新:使用一些 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);
        }

初始版本:


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

1

另一种略有不同的变体(经典但简单实用):

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

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接