Разделить строку / число на каждый N-й символ / число? - PullRequest
58 голосов
/ 09 ноября 2010

Мне нужно разбить число на четные части, например:
32427237 должно стать 324 272 37
103092501 должен стать 103 092 501

Я уверен, что мог бы просто перейти к следующим числам, но я уверен, что есть более эффективный способ, так как я не хочу пропустить символы в этих числах - сами числа могут быть любой длины, так что если число было 1234567890, я хотел бы, чтобы это было разделено на эти части 123 456 789 0

Я видел примеры на других языках, таких как Python и т. Д., Но я недостаточно хорошо их понимаю, чтобы преобразовать их в C # - циклически перебирая символы, а затем на третьем получая предыдущий, а затем этот индекс, чтобы получить раздел строка может сделать работу, но я открыт для предложений о том, как добиться этого лучше.

Ответы [ 13 ]

107 голосов
/ 09 ноября 2010

Если вам нужно сделать это во многих местах кода, вы можете создать необычный метод расширения:

static class StringExtensions {

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

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

}

Затем вы можете использовать его следующим образом:вывод 324 272 37 по желанию.

8 голосов
/ 09 ноября 2010

Вы можете использовать простой цикл 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();
6 голосов
/ 09 ноября 2010

Правила 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()));
5 голосов
/ 12 июля 2016

Это на полдесяти лет позже, но:

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()));
5 голосов
/ 09 ноября 2010

Один очень простой способ сделать это (не самый эффективный, но не на порядок медленнее, чем самый эффективный).

    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;
    }
3 голосов
/ 09 ноября 2010

Метод расщепления:

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 голосов
/ 09 ноября 2010

Мне нравится, потому что это круто, хотя и не супер эффективно:

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();
2 голосов
/ 09 ноября 2010

Я бы сделал что-то подобное, хотя я уверен, что есть и другие способы.Должен работать очень хорошо.

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();
}
1 голос
/ 26 августа 2017

Хорошая реализация, использующая ответы на другие вопросы 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

1 голос
/ 03 июля 2016

Если вы знаете, что длина всей строки в точности делится на размер детали, используйте:

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, но вы можете добавить .ToArray () или .ToList () в конце, если вам нужна строка [] или значение List .

...