
Для сегодняшнего упражнения нам дается абзац в виде очень длинной строки. Нам также рекомендуется, чтобы длина каждой строки не превышала 30 символов, включая пробелы и знаки препинания. Кроме того, слова не могут переносить строки, и каждая строка должна заканчиваться словом или словом с соответствующими знаками препинания. Кроме того, пробелы в одной строке должны быть равномерно распределены между словами.
Прежде чем мы начнем: разделяй и властвуй
Как всегда, нам нужно полностью сформулировать намерения на простом английском языке, поэтому в данном случае:
- Нам нужно разбить строку на массив содержащихся в ней слов.
- Затем нам понадобятся еще два пустых массива. В первом мы собираемся снова добавлять слова, пока не достигнем лимита строк. Второй будет содержать все линии, которые мы реконструировали.
- Затем нам нужна переменная для подсчета символов в строке. Каждый раз, когда мы просматриваем слово, мы собираемся обновить это число, чтобы отслеживать максимальное количество символов в строке.
Мы собираемся создать две функции для достижения наших целей. Первый создаст строки, а второй добавит пробелы, пока мы не достигнем целевого предела символов. Давайте сосредоточимся на первом.
Наша скелетная функция вместе с текстом для выравнивания:
const paragraph = ‘Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.’;
lineBuilder = (text) => {
}
lineBuilder(paragraph);
Теперь нам нужно инициализировать несколько переменных:
lineBuilder = (text) => {
// This will hold all the words in an array
const splitParagraph = longText.split(‘ ‘);
// This one will hold a line at a time.
let wordLine = [];
// This one will hold ALL of our lines
let allLines = [];
// We’ll use this one to keep track of our characters per line.
let wordCharsSubtotal = 0;
}
Теперь нам нужно перебрать наш массив слов:
lineBuilder = (text) => {
const splitParagraph = longText.split(‘ ‘);
let wordLine = [];
let allLines = [];
let wordCharsSubtotal = 0;
splitParagraph.forEach(word => {
wordCharsSubtotal += word.length;
const lineCharsRemaining = charLimit — wordCharsSubtotal — (wordLine.length — 1);
if (lineCharsRemaining > 0) {
wordLine.push(word);
} else {
allLines.push(wordLine);
wordLine = [word];
wordCharsSubtotal = word.length;
}
});
}
Здесь происходит следующее: мы просматриваем каждое слово, добавляем количество его символов к счетчику, а затем выясняем, сколько символов у нас осталось. Если у нас есть место, мы помещаем это слово в массив, а если нет, мы начинаем со следующего слова, пока не закончим.
Если бы мы занесли в console.log наши текущие результаты, мы бы получили что-то вроде этого:
[ [ 'Lorem', 'ipsum', 'dolor', 'sit', 'amet,' ], [ 'consectetur', 'adipiscing', 'elit,' ], [ 'sed', 'do', 'eiusmod', 'tempor' ], [ 'incididunt', 'ut', 'labore', 'et', 'dolore' ], [ 'magna', 'aliqua.', 'Ut', 'enim', 'ad', 'minim' ], [ 'veniam,', 'quis', 'nostrud' ], [ 'exercitation', 'ullamco', 'laboris' ], [ 'nisi', 'ut', 'aliquip', 'ex', 'ea', 'commodo' ], [ 'consequat.', 'Duis', 'aute', 'irure' ], [ 'dolor', 'in', 'reprehenderit', 'in' ], [ 'voluptate', 'velit', 'esse', 'cillum' ], [ 'dolore', 'eu', 'fugiat', 'nulla' ], [ 'pariatur.', 'Excepteur', 'sint' ], [ 'occaecat', 'cupidatat', 'non' ], [ 'proident,', 'sunt', 'in', 'culpa', 'qui' ], [ 'officia', 'deserunt', 'mollit', 'anim' ] ]
Хорошо, у нас есть многомерный массив, который нам нужно пройти, чтобы добавить все нужные нам пробелы:
allLines.push(wordLine);
const finalLines = allLines.map(line => {
const numLetterChars = line.join('').length;
const spaceCharsNeeded = charLimit - numLetterChars;
const lineWithSpaces = addSpaces(line, spaceCharsNeeded, 0);
return lineWithSpaces.join('');
});
finalLines.forEach(line => {
console.log(line);
});
Как вы помните, мы уже поместили все строки в wordLine. Мы делаем это здесь снова, потому что, если мы этого не сделаем, у нас в конце концов закончатся слова и мы не попадем в оператор else. Если вы хотите проверить его, запустите его как со вторым нажатием, так и без него, вы увидите, как он пропускает последнюю строку.
Итак, мы отображаем наш многомерный массив и подсчитываем количество символов, подсчитывая все символы, а затем вычитаем это количество из нашего предела символов, чтобы выяснить, сколько пробелов нам нужно, чтобы достичь предела символов. Затем мы запускаем другую функцию (которую мы еще не написали), чтобы добавить необходимые пробелы.
Последний шаг: добавление пробелов
Теперь нам нужно написать последнюю функцию, которую мы вызвали в последней. Как вы можете догадаться, он принимает три параметра: строку, количество символов, которые нам нужно, и счетчик для отслеживания добавленных пробелов:
function addSpaces(line, spaceCharsNeeded, spacesCharsAdded) {
for (let i = 0; i < line.length - 1; i++) {
if (spaceCharsNeeded - spacesCharsAdded > 0) {
line[i] += ' ';
spacesCharsAdded += 1;
}
}
if (spaceCharsNeeded > spacesCharsAdded) {
return addSpaces(line, spaceCharsNeeded, spacesCharsAdded);
}
return line;
}
Итак, мы начинаем цикл for со счетчиком, и пока счетчик меньше длины текущей строки-1, мы увеличиваем счетчик на единицу. На каждой итерации мы используем счетчик, чтобы получить позицию текущего слова в массиве и добавить пробел, затем мы добавляем к нему пробел и увеличиваем счетчик символов. Это происходит только в том случае, если есть еще символы для заполнения. Затем мы добавляем немного рекурсии, чтобы функция вызывала сама себя, если еще есть место для добавления дополнительных пробелов.
Полный код:
const paragraph = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
const charLimit = 30;
function lineBuilder(text) {
const splitParagraph = text.split(' ');
let allLines = [];
let wordLine = [];
let wordCharsSubtotal = 0;
splitParagraph.forEach(word => {
wordCharsSubtotal += word.length;
const lineCharsRemaining =
charLimit - wordCharsSubtotal - (wordLine.length - 1);
if (lineCharsRemaining > 0) {
wordLine.push(word);
} else {
allLines.push(wordLine);
wordLine = [word];
wordCharsSubtotal = word.length;
}
});
allLines.push(wordLine);
const finalLines = allLines.map(line => {
const numLetterChars = line.join('').length;
const spaceCharsNeeded = charLimit - numLetterChars;
const lineWithSpaces = addSpaces(line, spaceCharsNeeded, 0);
return lineWithSpaces.join('');
});
finalLines.forEach(line => {
console.log(line);
});
}
addSpaces = (line, spaceCharsNeeded, spacesCharsAdded) => {
for (let i = 0; i < line.length - 1; i++) {
if (spaceCharsNeeded - spacesCharsAdded > 0) {
line[i] += ' ';
spacesCharsAdded += 1;
}
}
if (spaceCharsNeeded > spacesCharsAdded) {
return addSpaces(line, spaceCharsNeeded, spacesCharsAdded);
}
return line;
}
lineBuilder(paragraph);