每N个字符/数字分割一个字符串/数字?


71

例如,我需要将数字分成偶数部分:
32427237需要变成324 272 37
103092501需要变成103 092 501

我敢肯定,我只能继续输入数字,但是我确定有一种更有效的方法,因为我不想错过这些数字中的字符-数字本身可以是任意长度,所以如果数字是1234567890我希望它分成这些部分123 456 789 0

我已经看过其他语言(例如Python等)中的示例,但我对它们的理解还不够好,无法将它们转换为C#-遍历字符,然后在第三个字符处获取前一个字符,然后使用该索引获取字符串部分做这项工作,但我愿意就如何更好地完成这项工作提出建议。


1
您想将字符串分成三个单独的字符串,还是要插入空格?
Dirk Vollmar,2010年

2
stackoverflow.com/questions/3760152/…。所有答案都在Java中,但您可以轻松地将其移植到c#。
艾米尔(Emil)2010年

它们将是三个单独的字符串
RoguePlanetoid 2010年

Answers:


130

如果必须在代码中的许多地方执行此操作,则可以创建一个奇特的扩展方法:

static class StringExtensions {

  public static IEnumerable<String> SplitInParts(this String s, Int32 partLength) {
    if (s == null)
      throw new ArgumentNullException(nameof(s));
    if (partLength <= 0)
      throw new ArgumentException("Part length has to be positive.", nameof(partLength));

    for (var i = 0; i < s.Length; i += partLength)
      yield return s.Substring(i, Math.Min(partLength, s.Length - i));
  }

}

然后可以像这样使用它:

var parts = "32427237".SplitInParts(3);
Console.WriteLine(String.Join(" ", parts));

输出是324 272 37所需的。

当您将字符串分成几部分时,即使这些子字符串已存在于原始字符串中,也会分配新的字符串。通常,您不必太担心这些分配,但是使用现代C#可以通过稍微更改扩展方法以使用“跨度”来避免这种情况:

public static IEnumerable<ReadOnlyMemory<char>> SplitInParts(this String s, Int32 partLength)
{
    if (s == null)
        throw new ArgumentNullException(nameof(s));
    if (partLength <= 0)
        throw new ArgumentException("Part length has to be positive.", nameof(partLength));

    for (var i = 0; i < s.Length; i += partLength)
        yield return s.AsMemory().Slice(i, Math.Min(partLength, s.Length - i));
}

返回类型更改为,public static IEnumerable<ReadOnlyMemory<char>>并通过调用Slice未分配的源来创建子字符串。

请注意,如果你在某些时候必须转换ReadOnlyMemory<char>string使用的API在一个新的字符串已被分配。幸运的是,ReadOnlyMemory<char>除此以外,还有许多.NET Core API可以使用,string因此可以避免分配。


2
恕我直言,扩展方法在这里是矫kill过正。所讨论的“数量”是a特定的事物类型,例如订单号。如果可以将扩展方式限制为仅适用于订单号,则可以。由于可以将其应用于碰巧存储在字符串中的任何实体,因此会破坏封装。
Binary Worrier,2010年

确实,我自己想到了一种方法,该方法可以将字符串拆分成任意大小的部分-可以尝试一下!
RoguePlanetoid 2010年

2
只是从编程指南中提醒您一些扩展方法:“通常,我们建议您仅在必要时谨慎地实施扩展方法。” 抱歉,我只是认为扩展方法已被过度使用。
steinar 2010年

2
如果您不想使用扩展方法,请删除this关键字并适当地重命名类和方法。我认为此特定方法相当通用(并非特定于订单号),并且是扩展方法的不错选择。将类放在一个单独的命名空间中,使开发人员可以决定是否要启用扩展方法,就像添加一样using System.Linq将大量扩展方法添加到中IEnumerable<T>
Martin Liversage 2010年

9

您可以使用简单的for循环在第n个位置插入空格:

string input = "12345678";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
    if (i % 3 == 0)
        sb.Append(' ');
    sb.Append(input[i]);
}
string formatted = sb.ToString();

这类似于我最初要创建的内容,但是有兴趣查看其他替代方法
RoguePlanetoid 2010年

此解决方案在第一个字符之前插入一个空格。
琼·查曼特

6

LINQ规则:

var input = "1234567890";
var partSize = 3;

var output = input.ToCharArray()
    .BufferWithCount(partSize)
    .Select(c => new String(c.ToArray()));

更新:

string input = "1234567890";
double partSize = 3;
int k = 0;
var output = input
    .ToLookup(c => Math.Floor(k++ / partSize))
    .Select(e => new String(e.ToArray()));

2
System.Linq.EnumerableEx.BufferWithCount是.NET(Rx)的Reactive Extensions的一部分:msdn.microsoft.com/en-us/devlabs/ee794896.aspx。您必须下载并安装此代码才能运行代码。
Martin Liversage 2010年

1
谢谢我以前没有看过BufferWithCount-现在我知道为什么-我已经安装了Rx,所以可能对其他用途很有用。
RoguePlanetoid 2010年

5

一种执行此操作的非常简单的方法(不是最有效的方法,但是也不会比最有效的方法慢几个数量级)。

    public static List<string> GetChunks(string value, int chunkSize)
    {
        List<string> triplets = new List<string>();
        while (value.Length > chunkSize)
        {
            triplets.Add(value.Substring(0, chunkSize));
            value = value.Substring(chunkSize);
        }
        if (value != "")
            triplets.Add(value);
        return triplets;
    }

继承人

    public static List<string> GetChunkss(string value, int chunkSize)
    {
        List<string> triplets = new List<string>();
        for(int i = 0; i < value.Length; i += chunkSize)
            if(i + chunkSize > value.Length)
                triplets.Add(value.Substring(i));
            else
                triplets.Add(value.Substring(i, chunkSize));

        return triplets;
    }

通用n版本会更好。
st0le 2010年

5

这已经晚了五年,但是:

int n = 3;
string originalString = "32427237";
string splitString = string.Join(string.Empty,originalString.Select((x, i) => i > 0 && i % n == 0 ? string.Format(" {0}", x) : x.ToString()));

2
我一直想知道,既然有一个LINQ解决方案,那就来了!
RoguePlanetoid

4

分割方法:

public static IEnumerable<string> SplitInGroups(this string original, int size) {
  var p = 0;
  var l = original.Length;
  while (l - p > size) {
    yield return original.Substring(p, size);
    p += size;
  }
  yield return original.Substring(p);
}

要以字符串形式加入,并用空格分隔:

var joined = String.Join(" ", myNumber.SplitInGroups(3).ToArray());

编辑:我更喜欢Martin Liversage解决方案:)

编辑2:修复了一个错误。

编辑3:添加了代码以将字符串重新加入。


2

我会做这样的事情,尽管我确定还有其他方法。应该表现不错。

public static string Format(string number, int batchSize, string separator)
{      
  StringBuilder sb = new StringBuilder();
  for (int i = 0; i <= number.Length / batchSize; i++)
  {
    if (i > 0) sb.Append(separator);
    int currentIndex = i * batchSize;
    sb.Append(number.Substring(currentIndex, 
              Math.Min(batchSize, number.Length - currentIndex)));
  }
  return sb.ToString();
}

2

我喜欢这是因为它很酷,尽管效率不是很高:

var n = 3;
var split = "12345678900"
            .Select((c, i) => new { letter = c, group = i / n })
            .GroupBy(l => l.group, l => l.letter)
            .Select(g => string.Join("", g))
            .ToList();

我本人只喜欢Linq,但效率是
必需的

2

如果您知道整个字符串的长度完全可以被部分大小整除,请使用:

var whole = "32427237!";
var partSize = 3;
var parts = Enumerable.Range(0, whole.Length / partSize)
    .Select(i => whole.Substring(i * partSize, partSize));

但是,如果有可能整个字符串的末尾可能会有小数部分,则您需要稍微复杂一些:

var whole = "32427237";
var partSize = 3;
var parts = Enumerable.Range(0, (whole.Length + partSize - 1) / partSize)
    .Select(i => whole.Substring(i * partSize, Math.Min(whole.Length - i * partSize, partSize)));

在这些示例中,部件将是IEnumerable,但是如果需要string []或List <string>值,则可以在末尾添加.ToArray()或.ToList()。


如果您认为自己正在为接受的答案增加价值,则应在已经回答的问题上添加自己的答案。看起来并非如此。
Marco Scabbiolo '16

我不明白 这是该问题的第十个答案,只有一个语句(使用Linq)可以完成第三个问题,我相信这是其中三个方法中最有效的。添加这个不同且可能更好的答案是否错误? ?
戴夫·兰伯特

1

尝试这个:

Regex.Split(num.toString(), "(?<=^(.{8})+)");

有趣的答案,但是您能解释一下正则表达式吗?
kotchwane

1

一个很好的实现,它使用其他StackOverflow问题的答案:

"32427237"
    .AsChunks(3)
    .Select(vc => new String(vc))
    .ToCsv(" ");  // "324 272 37"

"103092501"
    .AsChunks(3)
    .Select(vc => new String(vc))
    .ToCsv(" "); // "103 092 501"

AsChunks():https://stackoverflow.com/a/22452051/538763

ToCsv():https ://stackoverflow.com/a/45891332/538763


0

这可能是个话题,因为我不知道您为什么要以这种方式设置数字格式,因此如果无关紧要,请忽略此信息...

在不同文化中,如何显示整数是不同的。您应该以本地独立的方式执行此操作,以便以后更轻松地本地化更改。

int.ToString采用不同的参数,可用于格式化不同的区域性。在“N”参数为您提供了特定的文化分组的标准格式。

steve x字符串格式也是一个很好的资源。


它们只是数字,我不遵循任何一种正常的数字格式,这就是为什么我提到字符串/数字的原因,因为我将使用它们来处理需要这种特殊格式的东西。
RoguePlanetoid 2010年

0

为了分割字符串并返回每个位置具有特定字符数的字符串列表,这是我的功能:

public List<string> SplitStringEveryNth(string input, int chunkSize)
    {
        var output = new List<string>();
        var flag = chunkSize;
        var tempString = string.Empty;
        var lenght = input.Length;
        for (var i = 0; i < lenght; i++)
        {
            if (Int32.Equals(flag, 0))
            {
                output.Add(tempString);
                tempString = string.Empty;
                flag = chunkSize;
            }
            else
            {
                tempString += input[i];
                flag--;
            }

            if ((input.Length - 1) == i && flag != 0)
            {
                tempString += input[i];
                output.Add(tempString);
            }
        }
        return output;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.