Printing Javascript split() array and converting undefined values to strings - javascript

I am trying to convert a string to words, and then print these using javascript and html5 canvas. The string can be any length, but I am using 50 as a max value of words (separated by a space). Right now I have the following to create the array:
var wordArray = kstring.split(" ", 50);
for(var k = 0; k < wordArray.length; k++)
{
if(typeof wordArray[k] == 'undefined')
wordArray[k] = " .";
}
and then print using:
ctx.fillText(wordArray[0] + " " + wordArray[1] + " " + wordArray[2] + " " + wordArray[3] + " " + wordArray[4], leftOffset, txtHeight);
ctx.fillText(wordArray[5] + " " + wordArray[6] + " " + wordArray[7] + " " + wordArray[8] + " " + wordArray[9], leftOffset, txtHeight+20);
etc.
However, when the text prints, any undefined values print as "undefined" instead of " ." It seems that I am going about checking for the undefined value the wrong way, but I'm not sure what else to try.
Additionally, if anyone has any better suggestions for how to achieve this goal (convert a string to words and then print 5 words at a time). Please feel free to suggest some better options.
Thanks

There won't be any undefined values in the array returned by .split(). You're getting undefined because your print code has hardcoded indexes higher than the highest index in the array.
Sorry, I don't have time right now to test this, or explain it beyond mentioning that .slice() creates a new array extracting a range from the source array, and .join() is (obviously) the opposite of .split(), but maybe you could try something like this:
var wordArray = kstring.split(" ", 50),
i, h, l
wordsPerLine = 5,
lineHeight = 20;
for (i=0, h=0, l=wordArray.length; i < l; i+=wordsPerLine, h+=lineHeight) {
ctx.fillText( wordArray.slice(i, Math.min(l, i+wordsPerLine)).join(" "),
leftOffset, txtHeight + h);
}

Related

Am I correct about .toFixed() and decimals?

I gave an example of using .tofixed() with math, functions, and arrays, to a beginner coder friend who has been reviewing these topics in his class.
const bananaX = 9;
const bananaY = 2.9768;
bananaArray = [bananaX , bananaY];
console.log("X before array = " + bananaX);
console.log("Y before array = " + bananaY + '\n')
console.log("X,Y after array = " + bananaArray + '\n')
console.log("Value of X in array: " + bananaArray[0]+ '\n')
console.log("Value of Y in array: " + bananaArray[1]+ '\n')
function bananaDivision (bananaArray){
console.log("Value of X after function = " + bananaX);
console.log("Value of Y after function = " + bananaY + '\n')
let bananaDivided = Math.abs(bananaX/bananaY );
console.log (`X divided by Y = + ${bananaDivided}` + '\n')
let bananaFixed = bananaDivided.toFixed(2);
console.log("After using .toFixed(2) : " + bananaFixed + '\n');
};
bananaDivision();
They were understanding and following along no problem.
Then they asked me - "What if we put a decimal in the .toFixed ?"
So I ran:
const bananaX = 9;
const bananaY = 2.9768;
bananaArray = [bananaX , bananaY];
console.log("X before array = " + bananaX);
console.log("Y before array = " + bananaY + '\n')
console.log("X,Y after array = " + bananaArray + '\n')
console.log("Value of X in array: " + bananaArray[0]+ '\n')
console.log("Value of Y in array: " + bananaArray[1]+ '\n')
function bananaDivision (bananaArray){
console.log("Value of X after function = " + bananaX);
console.log("Value of Y after function = " + bananaY + '\n')
let bananaDivided = Math.abs(bananaX/bananaY );
console.log (`X divided by Y = + ${bananaDivided}` + '\n')
let bananaFixed = bananaDivided.toFixed(2);
let bananaFixed1 = bananaDivided.toFixed(.69420);
let bananaFixed2 = bananaDivided.toFixed(1.69420);
console.log("After using .toFixed(2) : " + bananaFixed + '\n');
console.log("After using .toFixed(.69420) : " + bananaFixed1 + '\n');
console.log("After using .toFixed(1.69420) : " + bananaFixed2 + '\n');
};
bananaDivision();
I explained it as that .toFixed is looking at the first number within the () and that the decimals are ignored.
Am I correct? For my own curiousity, is there a crazy way to break .toFixed() so that it actually uses decimals? I'm experimenting atm but wanted to know if someone already figured that out.
I explained it as that .toFixed is looking at the first number within the () and that the decimals are ignored.
This would be correct. That is essentially what happens.
For full correctness, the input of toFixed() will be converted to an integer. The specification states that the argument must first be converted to a number - NaN will be converted to a zero. Numbers with a fractional part will be rounded down.
Which means that if you pass any number, you essentially get the integer part of it.
It also means that non-numbers can be used:
const n = 3;
console.log(n.toFixed("1e1")); // 1e1 scientific notation for 10
You're close, since toFixed() expects an integer it will handle converting decimal numbers before doing anything else. It uses toIntegerOrInfinity() to do that, which itself uses floor() so the number is always rounded down.
Most of Javascript handles type conversion implicitly, so it's something you should really understand well if you don't want to run into problems. There's a free book series that explains that concept and a lot of other important Javascript knowledge very well, it's called You Don't Know JS Yet.
just a demo how .tofixed works !!!!!!
function roundFloat(x, digits) {
const arr = x.toString().split(".")
if (arr.length < 2) {
return x
}else if(arr[1] === ""){
return arr[0]
}else if(digits < 1){
return arr[0]
}
const st = parseInt(x.toString().split(".")[1]);
let add = false;
const rudgt = digits
const fX = parseInt(st.toString().split("")[rudgt]);
fX > 5 ? add = true : add = false
nFloat = parseInt(st.toString().split("").slice(0, rudgt).join(""))
if (add) {
nFloat += 1
}
const repeat0 = (() => {
if (rudgt - st.toString().length < 0) {
return 0
}
return rudgt - st.toString().length
})()
const output = x.toString().split(".")[0] + "." + nFloat.toString() + "0".repeat(repeat0);
return output
}
console.log(roundFloat(1.200, 2))

How to concatenate two variables in a array

I am pushing values to a empty array using push(), but when I console log the array I am getting a single character per line. I am trying to concatenate two variables into one line/space.
// Example
walking.CordX = 5;
walking.CordY = 2;
walking.wLog.push("x" + " " + walking.cordX, "y" + " " + walking.cordY);
console.log(wLog);
//Will Show
1: x5
2: y2
How can I change it to get it like:
1: x5 y2
You can simply use multi-line syntax from es6.
let arr = [], x=5, y=7;
arr.push(`x${x} y${y}`);
console.log(arr);
walking.wLog.push("x" + " " + walking.cordX + " " + "y" + " " + walking.cordY);
This should work.

Couple of questions about code that hides text strings from output

Hello I started learning JavaScript and esterday I asked to help me hide NaN strings of array from output. Some guys helped me.. But I got new questions.
Here the link to answers
For this code,
if (typeof(degFahren[loopCounter]) === 'string') continue;
What's happening in there? As I can see If degFahren equal to text string, script will go ahead, but it works another way around and handle numbers for output.
For this code
if (parseInt(degFahren[loopCounter]) != "NaN")
It doesnt hide NaN strings at all. Shows all strings from array. Why?
Here block of code that does't work
for (loopCounter = 0; loopCounter <=6; loopCounter++){
if (parseInt(degFahren[loopCounter]) != "NaN")
degCent[loopCounter] = convertToCentigrade(degFahren[loopCounter]);
document.write ("Value " + loopCounter + " was " + degFahren[loopCounter] + " degrees Fahrenheit");
document.write (" which is " + degCent[loopCounter] + " degrees centigrade<br />");
}
Your assumptions are right, but the code fails because you missed the braces. You should add braces after if condition
for (loopCounter = 0; loopCounter <=6; loopCounter++){
if (parseInt(degFahren[loopCounter]) != "NaN") {
degCent[loopCounter] = convertToCentigrade(degFahren[loopCounter]);
document.write ("Value " + loopCounter + " was " + degFahren[loopCounter] + " degrees Fahrenheit");
document.write (" which is " + degCent[loopCounter] + " degrees centigrade<br />");
}
}
As I can see If degFahren equal to text string, script will go ahead
degFahren is apparently expected to be an array. It doesn't test whether degFahren is a string, it tests whether the current element being iterated over (which is inside the array) is a string.
It doesnt hide NaN strings at all. Shows all strings from array. Why?
NaN is not a string; it is a primitive value. But NaN !== NaN; you should use the isNaN() function instead.
You should also avoid implicitly creating global variables. It will be easier to read if you abstract the temperatures instead of messing with indicies:
for (loopCounter = 0; loopCounter <=6; loopCounter++){
const tempF = degFahren[loopCounter];
if (isNaN(tempF)) continue;
const tempCentigrade = convertToCentigrade(tempF);
document.write ("Value " + loopCounter + " was " + tempF + " degrees Fahrenheit");
document.write (" which is " + tempCentigrade + " degrees centigrade<br />");
}

Regex: How to return matches that are not in the bracket

So I technically already solved this issue, but I was hoping for a better solution using some funky regex.
The issue is:
We got strings this:
2+{2+(2)},
10+(20+2)+2
The goal is to match the 'plus' signs that are not in any sort of bracket.
i.e. in the previous strings it should match
2 + {2+(2)} ,
10 + (20+2) + 2
at the moment what I am doing is matching all plus signs, and then checking to see if the sign has any bracket in front of it (using regex), if it does then get rid of it.
I was hoping for a neater regex solution, is that possible?
To reiterate, I need the location of the strings, at the moment I am using javascript to do this, so ideally a js solution is preferred, but the pattern is really what I am looking for.
You could perhaps just replace everything inside () or {} with spaces:
'10 + (20+2) + 2'.replace(/\([^)]*?\)|\{[^}]*?\}/g, m => ' '.repeat(m.length));
This would result in
10 + + 2
Meaning the position of the strings aren't changed.
Note: It won't work well with nested things of the same type, ex (1 + (1 + 1) + 1), but it works with (1 + { 1 + 1 } + 1).
Bigger solution, using the same logic, but that works with nested stuff
var input = '10 + { 1 + (20 + (1 + { 3 + 3 } + 1) + 2) + 2 }';
var result = [];
var opens = 0;
for (var i = 0; i < input.length; ++i) {
var ch = input[i];
if (/\(|\{/.test(ch)) {
opens++;
result[i] = ' ';
}
else if (/\)|\}/.test(ch)) {
opens--;
result[i] = ' ';
}
else {
if (!opens) result[i] = input[i];
else result[i] = ' ';
}
}
result = result.join('');
// "10 + "

js last array item is undefined

I am trying to make a hangman game and in the beginning the game asks the user for the word. Once it has the word it fills the word letters one by one in an array using a for loop. Unfortunately the last array element is always undefined for some reason.
Code(JS):
for(i=0;i<word.length;i++)
{
if(i == word.length - 1)
{
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
}
else
{
pcArray.push(word[i]);
}
}
This has a very simple reason: you are not adding the last letter to your pcArray. Let's assume our word is 'bird' (because bird is a word). Your code would go through the letters b, i and r and push those to your array, so far so good. But when it hits the d, it is at position word.length-1 - because the array length starts at 1 but the index starts at 0. Your if statement prevents it from pushing the last letter to the word. There are two solutions:
First, you could simply remove the else statement:
for(i=0;i<word.length;i++){
if(i == word.length - 1){
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
}
pcArray.push(word[i]);
}
That will push every letter every time! However, There is a more efficient way:
for(i=0;i<word.length;i++)
pcArray.push(word[i]);
wordLettersLeft = word.length;
$("#cEText").removeAttr("style");
$(".characterEnter").removeAttr("style");
$("#gBtn").text("Lopeta");
gameStarted = true;
pcArrayLength = pcArray.length;
lives = 4;
alert("Peli alkaa! Sinulla on " + lives + " yritystä jäljellä.");
alert("Vihje: " + hint);
alert("Sinulla on vielä " + wordLettersLeft + " arvattavaa kirjainta jäljellä.");
This way you will only execute your initial code once instead of checking the if every time. You know your loop will only run for as long as there are letters, so why even bother with the if?
As #Shilly mentions in the comments, you can forego the for loop altogether by doing this:
pcArray = word.split('');
Let's say someone's inputing the word "Test". For i === 3 which is the last iteration, you enter the if clause and you're missing out on the else clause, which is where you're doing:
pcArray.push(word[i]);
What you want is to do this anyway, regardless of whether you're in the if or the else, so you can just drop the else clause and do it anyway.
The last step of your loop does not execute pcArray.push(word[i]);. So obvioulsy, the last value is missing.
But if you want to convert a string into an array, just do this :
var pcArray = word.split('');

Categories