Страницы

Поиск по вопросам

среда, 4 марта 2020 г.

C# перенос слов в строке с разбивкой на определенную длину

#c_sharp


Есть строка: Quisque velit nisi, pretium ut lacinia in, elementum id enim. Nulla
porttitor accumsan tincidunt.

Нужно разбить ее на три части, но сохранять целые слова и переносить на следующую
строку только после окончания слова.
Например, разбиваем на три строки: 

Quisque velit nisi, pretium ut 
lacinia in, elementum id enim. 
Nulla porttitor accumsan tincidunt.


Сейчас использую вот такой простой код, но он режет целые слова:

int chunkSize = string.Length / 3;
int stringLength = string.Length;
for (int i = 0; i < stringLength; i += chunkSize)
{
    if (i + chunkSize > stringLength) chunkSize = stringLength - i;             
                      
    Console.WriteLine(string.Substring(i, chunkSize));
}


Получается на выходе:

Quisque velit nisi, pretium ut l
acinia in, elementum id enim. Nu
lla porttitor accumsan tincidunt
.


Подскажите как можно проще это реализовать? 

UPDATE

Важно: исходная строка может отличаться от приведенной выше. Может содержать любые
символы.

Нашел простое решение здесь https://stackoverflow.com/a/17571171/2127124

public static class ExtensionMethods
{
    public static string[] Wrap(this string text, int max)
    {
        var charCount = 0;
        var lines = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
        return lines.GroupBy(w => (charCount += (((charCount % max) + w.Length +
1 >= max) 
                        ? max - (charCount % max) : 0) + w.Length + 1) / max)
                    .Select(g => string.Join(" ", g.ToArray()))
                    .ToArray();
    }
}

    


Ответы

Ответ 1



Идея - найти индексы символов, по которым нужно разбить в идеале (на равные части). Найти все возможные варианты разбиений строки и выбрать вариант с наименьшей ошибкой. За ошибку я решил принять сумму абсолютных значений отклонений выбранных индексов от идеальных. static int Abs(int x) => x >= 0 ? x : -x; static void Main(string[] args) { // Входной текст var str = "Quisque velit nisi, pretium ut lacinia in, elementum id enim. Nulla porttitor accumsan tincidunt."; // Количество выходных строк var numOfParts = 3; // Перечень разделителей var delimeters = " "; // Индексы, по которым надо разбить в идеале var idealParts = Enumerable.Range(1, numOfParts - 1) .Select(x => ((str.Length - numOfParts + 1) * x + numOfParts / 2) / numOfParts) .ToArray(); // индексы всех имеющихся мест, по которым можно разбить var indices = str.Select((c, i) => (c: c, i: i)) .Where(t => delimeters.Contains(t.c)) .Select(t => t.i) .ToArray(); // indices.Length ^ numOfParts var numOfSp = Enumerable.Range(0, numOfParts - 1) .Aggregate(1, (m, x) => m * indices.Length); // Генерируем все возможные комбинации var splits = new int[numOfSp][]; for (int d = 0; d < numOfSp; ++d) { var z = d; splits[d] = new int[numOfParts - 1]; for (int i = numOfParts - 2; i >= 0; --i) { splits[d][i] = z % indices.Length; z /= indices.Length; } } // Для каждой комбинации подсчитываем ошибку var spWithEr = splits.Select(s => (s: s, er: s.Select((x, i) => Abs(indices[x] - idealParts[i])).Sum())) .ToArray(); // Находим минимальную ошибку var minEr = spWithEr.Min(t1 => t1.er); // Выбираем комбинацию с наименьшей ошибкой var minSp = spWithEr.First(t => t.er == minEr).s; // Отбираем индексы var sp = new[] { -1 }.Concat(minSp.Select(x => indices[x]) .Concat(new[] { str.Length })) .ToArray(); // Разбиваем на строки по индексам из sp for (int i = 0; i < sp.Length - 1; ++i) Console.WriteLine(str.Substring(sp[i] + 1, sp[i + 1] - sp[i] - 1)); Console.ReadLine(); } Вывод: Quisque velit nisi, pretium ut lacinia in, elementum id enim. Nulla porttitor accumsan tincidunt. Оверхед ли это - решать вам

Ответ 2



Разбиваем строку на слова с помощью метода Split и задаем максимальное количество символов в строке. Затем мы строим каждую строку из слов, разделяя их пробелами и проверяя не привысила ли длина текущий строки максимальную. Код получается довольно компактным, и пусть он скажет за себя) var inputString = @"Quisque velit nisi, pretium ut lacinia in, elementum id enim. Nulla porttitor accumsan tincidunt"; var words = inputString.Split(new Char[] { ' ' }); var maxLengthString = 53; int wordIndex = 0; var spaceLetter = " "; var currentLine = new StringBuilder(); while (true) { if (currentLine.Length + words[wordIndex].Length + 1 > maxLengthString)// Определяем не привысила ли текущая строка максимальную длину { Console.WriteLine(currentLine); currentLine.Remove(0, currentLine.Length); } currentLine.Append(words[wordIndex]); currentLine.Append(spaceLetter); wordIndex++; if(wordIndex == words.Length) { Console.WriteLine(currentLine); break; } }

Комментариев нет:

Отправить комментарий