Reputation: 363
I have the following while loop as part of my text justify function. The idea is that I have text strings (str
) that need to be justified (spaces added to existing spaces in between words) to equal to a given length (len
)
The catch is I can only add one space to an existing space at a time before I iterate over to the next space in the string and add another space there. If that's it for all spaces in the string and it's still not at the required length, I cycle back over to the original space (now two spaces) and add another. Then it goes to the next space between words and so on and so on. The idea is that any spaces between words in the string should not have a differential of more than one space (i.e. Lorem---ipsum--dolor--sit
, not Lorem----ipsum--dolor-sit
)
From my research, I decided that using a substring
method off the original string to add that first extra space, then I will increment the index and move to the next space in the string and repeat the add. Here's my code:
var indexOf = str.indexOf(" ", 0);
if ( indexOf > -1 ) {
while ( indexOf > -1 && str.length < len ) {
//using a regexp to find a space before a character
var space = /\s(?=\b)/.exec(str);
str = str.substring(0, indexOf + 1) + " " + str.substring(indexOf + 1);
//go to next space in string
indexOf = str.indexOf(space, indexOf + 2);
if ( indexOf === -1 ) {
//loops back to beginning of string
indexOf = str.indexOf(space, 0);
}
}
}
finalResults.push(str);
This code works most of the time, but I noticed that there are instances where the cycle of spacing is not correct. For example, it generates the following string:
sit----amet,--blandit
when the correct iteration would be
sit---amet,---blandit
Any assistance in making this code properly iterate over every space (to add one space) in the string once, then cycling back around to the beginning of the string to start over until the desired length is achieved would be most appreciated.
Upvotes: 0
Views: 287
Reputation: 16033
This function adds the spaces using a global replace, carefully limiting the text size.
function expand (txt, colwidth) {
txt = txt.replace (/\s\s+/, ' '); // Ensure no multiple spaces in txt
for (var spaces = ' ', // Spaces to check for
limit = colwidth - txt.length; // number of additional spaces required
limit > 0; // do while limit is positive
spaces += ' ') // add 1 to spaces to search for
txt = txt.replace (RegExp (spaces, 'g'),
function (r) {
// If limit > 0 then add a space else do not.
return limit > 0 && --limit ? r + ' ' : r
});
return txt;
}
for (var w = 21; w--;) console.log (expand ('this is a test.', w));
Shows this on console:
this is a test.
this is a test.
this is a test.
this is a test.
14 this is a test.
Upvotes: 1
Reputation: 28840
This solution
s
) into words in an array (a
)add
)rem
)add
spaces + one if rem
is not exhaustedCode
var s = "Caballo sin Nombre"; // assume one space between words
var len = 21; // desired length
var need = len - s.length;
var a = s.split(/ /); // split s
// need>0 and at least two words
if (need > 0 && a.length>1) {
var add = Math.floor(need / (a.length-1)) + 1; // all spaces need that (+existing)
var rem = need % (a.length-1); // remainder
var sp = '';
while (add-- > 0) sp += ' ';
// replace
var i,res = ''; // result
for (i=0 ; i<a.length-1 ; i++) {
res += a[i] + sp;
if (rem-- > 0) res += ' '; // remainder
}
res += a[i];
s = res;
}
console.log("'" + s + "' is " + s.length + " chars long.");
Upvotes: 1
Reputation: 12772
I think it's more efficient to compute the number spaces required in the beginning.
var s = "today is a friday";
var totalLength = 40;
var tokens = s.split(/\s+/);
var noSpaceLength = s.replace(/\s+/g,'').length;
var minSpace = Math.floor((totalLength - noSpaceLength)/(tokens.length-1));
var remainder = (totalLength - noSpaceLength) % (tokens.length-1);
var out = tokens[0];
for (var i = 1; i < tokens.length; i++) {
var spaces = (i <= remainder ? minSpace+1 : minSpace);
out += "-".repeat(spaces) + tokens[i];
}
$('#out').text(out);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="out"></div>
Upvotes: 1