Read Digital Numbers in JavaScript (Node.js)? - javascript

I have a text file in which digital characters are there like -
_ _ _ _ _ _ _ _ _ (line 1)
| _| _||_||_ |_ ||_||_| (line 2)
||_ _| | _||_| ||_| _| (line 3)
(line 4)
_ _ _ _ _ _ _ (line 5)
|_||_|| ||_||_ | | ||_ (line 6)
| _||_||_||_| | | | _| (line 7)
(line 8)
Invoice number format:
Each invoice number is constructed of 9 digits [0..9]
Invoice number is written using _ and | characters.
Invoice number input takes 4 lines.
The first 3 lines contain 27 characters.
The fourth line is blank.
The output should be -
723956789
490867715
I read the text file using fs module of node js like this and break every digital character in to three parts basically -
var fun = function(){
fs.readFile("./input1.txt", 'utf8', function(err, data) {
var i = 0;
console.log(data.length);
while(data[i] != "\n" && i<data.length) {
if(data[i] != " ") {
var str = "";
while(data[i]!= " " && data[i]!= "\n") {
str = str + data[i];
i++;
}
inputA.push(str);
} else {
i++;
}
}
i++;
console.log(i,inputA);
while(data[i] != "\n" && i<data.length) {
if(data[i] != " ") {
var str = "";
while(data[i]!= " " && data[i]!= "\n") {
str = str + data[i];
i++;
}
inputB.push(str);
// console.log(inputA);
} else {
i++;
}
}
i++;
console.log(i,inputB);
while(data[i] != "\n" && i<data.length) {
if(data[i] != " ") {
var str = "";
while(data[i]!= " " && data[i]!= "\n") {
str = str + data[i];
i++;
}
console.log(str);
inputC.push(str);
// console.log(inputA);
} else {
i++;
}
}
console.log(inputA);
console.log(inputB);
console.log(inputC);
})
}
But not able to read properly. Can any one help me to read and get the desired output.

Here are two functions in ES6 which do the job:
function getDigit(pattern) {
return {
" _ | ||_|": 0,
" | |": 1,
" _ _||_ ": 2,
" _ _| _|": 3,
" |_| |": 4,
" _ |_ _|": 5,
" _ |_ |_|": 6,
" _ | |": 7,
" _ |_||_|": 8,
" _ |_| |": 9,
" _ |_| _|": 9, // alternative 9
}[pattern];
}
function getNumber(lines) {
// Chop each line into 9 pieces of 3 chars:
lines = lines.map( line => line.match(/.../g) );
// Combine the pieces of each digit-pattern together:
return +lines[0].map ( (piece, i) => piece + lines[1][i] + lines[2][i] )
// Translate each pattern of 3x3=9 characters to a digit
.map(getDigit)
// Join digits together into one number
.join('');
}
// Sample data
const data =
' _ _ _ _ _ _ _ _ _ \n'
+ ' | _| _||_||_ |_ ||_||_|\n'
+ ' ||_ _| | _||_| ||_| _|\n'
+ '\n'
+ ' _ _ _ _ _ _ _ \n'
+ '|_||_|| ||_||_ | | ||_ \n'
+ ' | _||_||_||_| | | | _|';
const lines = data.split('\n');
var a = getNumber(lines.slice(0, 3));
var b = getNumber(lines.slice(4));
console.log(a);
console.log(b);

As Timo stated in the comments, it would be far preferable to ask whomever produced the text file to export their data in a sane format.
If this is not possible, here is one way to translate the numbers into something usable, though I have taken the liberty of changing the format of your first 9 to match the two other nines in your sample input.
If the 9s can be in two different formats, I would simply use a Map to catch both formats.
// Note the first 9 in the first number has been changed.
let input = `
_ _ _ _ _ _ _ _ _
| _| _||_||_ |_ ||_||_|
||_ _| _| _||_| ||_| _|
_ _ _ _ _ _ _
|_||_|| ||_||_ | | ||_
| _||_||_||_| | | | _|
`;
// Strip empty lines
let lines = input.split('\n').filter(Boolean);
// Format: line1 + line2 + line3
let translator = [
' _ | ||_|', //0
' | |', //1
' _ _||_ ', //2
' _ _| _|', //3
' |_| |', //4
' _ |_ _|', //5
' _ |_ |_|', //6
' _ | |', //7
' _ |_||_|', //8
' _ |_| _|', //9, or ' _ |_| |' if the other 9 format was correct
]
let nums = [];
// Each "number" is 3 lines long.
for (let i = 0; i < lines.length; i += 3)
{
let num = 0;
// There are 9 numbers per line, 3 characters per number per line
for (let n = 0; n < 27; n += 3)
{
let s = lines[i].substr(n, 3) + lines[i + 1].substr(n, 3) + lines[i + 2].substr(n, 3);
num = num * 10 + translator.indexOf(s);
}
nums.push(num);
}
console.log(nums[0] == 723956789, nums[0]);
console.log(nums[1] == 490867715, nums[1]);

Related

I cannot implement variable support

I am trying to implement 'variable declaration future' to my parsed language.
PEG.js source:
start
=begin line (pl)+ end
pl
=varx" " left:identifier" "to" "middle:integer line { left=middle;}
/
print"(" middle:identifier ")" line {alert(middle);}
line
="\n"
begin
="start"
print
="print"
if
="if"
equals
="equals"
gth
="greater than"
identifier
=[a-zA-Z]+ {return text();}
to
="to"
varx
="set"
end
="end"
integer "integer"
= digits:[0-9]+ { return Number(parseInt(digits.join(""), 10)); }
My custom input source:
start
set a to 5
print(a)
end
What output I got:
[
"start",
"
",
[
undefined,
undefined
],
"end"
]
And as alert I got only the variable name a no the value...
try this
all
= "start" nl _ ptp:putThenPrint+ _ "end"
{
var all = [];
ptp.forEach(it => {
all.push(it);
});
var r = []
all.forEach(tp => {
tp.toPrint.forEach(p => {
r.push(tp.values[p])
});
});
return "\n" + r.join("\n") + "\n";
}
putThenPrint
= _ mn:multiPutN _ pn:multiPrintN _
{
return {values:mn,toPrint:pn};
}
multiPrintN
= _ mp:printN+ _
{
var r = [];
mp.forEach(it => {
r.push(it);
});
return r;
}
multiPutN
= _ mp:putN+ _
{
var r = {};
mp.forEach(it => {
r[it[0]]=it[1];
});
return r;
}
putN
= _ "set " _ vn:varName _ "to " _ vv:n _ nl+ { return [vn, vv]}
printN
= _ "print(" _ n:varName _ ")" _ nl+ {return n;}
varName
= [a-zA-Z]+ {return text();}
n "integer number"
= _ [0-9]+ { return parseInt(text(), 10); }
nl "new line"
= [\n]
_ "whitespace"
= [ \t]*
this grammar does not support "if" and some other things you are trying to do in your grammar but it will give you a start up idea.
You need to elaborate more of what you want in text with more example and expected output

Regex test is getting failed in nodejs?

I have two sentences which I need to compare and produce the result. The sentences are listed below.
var msg = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End {#val#}"
var msg2 = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End 123"
Both the sentences are equal except for the val portion and it can be ignored. That's what below code is trying to do.
//Trying to add escape character for special characters
msg = msg.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
msg2 = msg2.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
//Adding space only if two {#val#} exists, else updating \\s* (can be many spaces or without spaces)
msg = msg.replace(/(^|.)\s($|.)/g, (x, g1, g2) => (x == "} {" ? x : g1 + "\\s\*" + g2));
//Replacing val with 1,29 (characters can be up to 29 in place of val)
var separators =/{#val#}|((\\s\*))/gi;
msg= msg.replace(separators, (x, y) => y ? y : ".(\\S{1,29})");
let regex = RegExp("^" + msg+ "$");
//Comparing two sentences
console.log(regex.test(msg2);
It is getting failed. I don't have issues with val and pace, but if i add special characters in the sentences it gives me failure result only.
At the end of the script, this is the value of msg:
Hi\s*this\s*is\s*DLT\s*test\s*~ !\s*# \#\s*\$\s*% \^\s*& \*\s*\(\s*\)\s* _\s*\-\s*\+\s*= \{\s*\[\s*\}\s*\]\s*\|\s*\\\s*: ;\s*" '\s*< \,\s*> \.\s*\?\s*/ End\s*\{\#val\#\}
And this is the value of msg2:
Hi this is DLT test ~ ! # \# \$ % \^ & \* \( \) _ \- \+ = \{ \[ \} \] \| \\ : ; " ' < \, > \. \? / End 123
The first is not a valid regular expression for the second, because
\{\#val\#\} does not match 123 (use instead: var separators =/\\{\\#val\\#\\}|((\\s\*))/gi;);
msg2 characters should not be escaped.
See a working example below:
var msg = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End {#val#}"
var msg2 = "Hi this is LT ~ ! # # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > . ? / End 123"
//Trying to add escape character for special characters
msg = msg.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&');
//Adding space only if two {#val#} exists, else updating \\s* (can be many spaces or without spaces)
msg = msg.replace(/(^|.)\s($|.)/g, (x, g1, g2) => (x == "} {" ? x : g1 + "\\s\*" + g2));
//Replacing val with 1,29 (characters can be upto 29 in place of val)
var separators =/\\{\\#val\\#\\}|((\\s\*))/gi;
msg = msg.replace(separators, (x, y) => y ? y : ".(\\S{1,29})");
let regex = RegExp("^" + msg+ "$");
//Comparing two sentences
console.log(regex.test(msg2)); //logs 'true'

JavaScript Hangman demo

I need to put an id of each div and then if I type or if you have another idea how to enter a letter, for example, the secret_word is emir so if I type E the lo dash (___) to deleted and replaced with E.
Unfortunately, this is how I learn javascript I am absolute beginner so I would appreciate any help or advice I don't know if it will make some bag in the future but this is a photo of how the divs are in the console and I might need to hardcode number 1 instead of var sw= ''; to I am really not sure.
Also, I think somehow with a prompt is a good way to get a word my teachers are my friends and they divided the task into pieces I can ask them or use StackOverflow. Also if you can refer me to some link where can I find some usable advice I would be greatly appreciated.
function getTheWord(){
//var secret_word = document.getElementById("secret").value;
secret_word = "emir";
var sw = '';
for(i=1; i <= secret_word.length;i++){
console.log(i);
console.log(sw);
sw += '<div style="display:inline-block;"> ___ </div>';
}
document.getElementById('secret').innerHTML = sw;
}
function GetValue()
{
var my_array= new Array("head","hand1","hand2","body","leg1","leg2");
var random_array = my_array[Math.floor(Math.random() * my_array.length)];
console.log(random_array);
document.getElementById("message").innerHTML=random_array;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="style.css" rel="stylesheet" type="text/css">
<title>Document</title>
</head>
<body onload="getTheWord();">
<input type="button" id="btnSearch" value="Search" onclick="GetValue();" />
<p id="message" ></p>
<div id="secret"></div>
<br>
<input type="text" id="secret" />
</body>
</html>
At the bottom of this post you will find a working hangman game. What follows is a attempt to explain how it works. As surprising as it may sound, there is much to say about this small program, thus I've decided to split my explanations into three parts :
The JavaScript builtins : a quick look at the native functions involved in this program.
The game's state and loop : an overview of the structure and logic of the program.
A bit of painting : a focus on the source code related to the program's output.
1. The JavaScript builtins
This section aims to draw a clear line between our own functions and the native functions involved in this program. I'm going to highlight key functions, how to use them, and how they interact with each other. With this basic knowledge in mind, you should be able to understand the program faster. Here is a summary table :
Name | Array | String | Usage -> Output
---------|---------|---------|-------------------------------------------
repeat | | X | "123".repeat(3) -> "123123123"
split | | X | "1|2|3".split("|") -> [1, 2, 3]
join | X | | [1, 2, 3].join("|") -> "1|2|3"
map | X | | [1, 2, 3].map(x => 2 * x) -> [2, 4, 6]
reduce | X | | [1, 2, 3].reduce((a, x) => a + x, 0) -> 6
indexOf | X | X | [1, 2, 3].indexOf(2) -> 1
concat | X | X | [1].concat([2, 3]) -> [1, 2, 3]
Although most of these functions are self-explanatory, I'd like to bring out a few points :
Some of these functions can be applied to both arrays and strings. indexOf for example can also be used like this : "123".indexOf(2).
join is the reverse function of split. It's often used to prepare the data for storage and output. For example, console.log("[" + [1, 2, 3].join(", ") + "]").
map takes an array, applies the given function to each item, and returns a new array. Easy to understand, more readable than a for loop, and extremely useful.
split, map and join are often used together. Stupid usage example here, but good to get the idea : "123".split("").map(x => 2 * x).join("") gives "246".
reduce is probably the most tricky function. Since there is only one call to this function, I won't go into details. All you need to know is that it gets the longest line in the "ASCII art". By the way, we could replace it with a good old for loop :
var CANVAS_WIDTH = 0;
for (var i = 0; i < HANGMAN.length; i++) {
CANVAS_WIDTH = Math.max(HANGMAN[i].length, CANVAS_WIDTH);
}
That's it for the JavaScript builtins. If you want more details, I can suggest you to Google "mdn [name of the function]". MDN is for Mozilla Developer Network, think of it as a manual for web developers.
2. The game's state and loop
The hangman game is a typical interactive program. When the player types something, the program updates it's state according to the input, gives a feedback to the player, and waits for the next input. This pattern repeats again and again until the end of the game : wait, input, update, output, wait, input, update, output, and so on... Three functions play a key role in this mechanism :
Name | Short description
-------------|------------------------------------------------------
main | Entry point of the program. Starts the game's loop.
isGameOver | Returns true or false depending on the game's state.
updateState | Contains the logic related to the player's input.
The functions' body is quite short and easy to read, so I won't describe the source code line by line, I leave this job to you. However, let me suggest you to read the entire section first.
The game's state is made of two variables, a fails counter and a progress array. The main function is in charge of initializing them. At starting, fails is set to 0, and progress is filled up with placeholders (_). Then, updateState takes care of keeping the variables up to date. A wrong guess increments the fails counter, while a good guess replaces the placeholders with the given letter. Let me show you :
> | secret = "secret",
| progress = ["_", "_", "_", "_", "_", "_"],
| state = { fails: 0, progress: progress }
< | {
| fails: 0,
| progress: ["_", "_", "_", "_", "_", "_"]
| }
> | updateState("e", secret, state),
| state
< | {
| fails: 0,
| progress: ["_", "e", "_", "_", "e", "_"]
| }
> | updateState("a", secret, state),
| state
< | {
| fails: 1,
| progress: ["_", "e", "_", "_", "e", "_"]
| }
The main function also initializes the game's loop. Then, each new input triggers one iteration. On each iteration, isGameOver checks the game's state in order to decide whether the program should keep on talking to the player. The dialog stops when either the secret is revealed (there is no remaining placeholder in the progress array) or the drawing is complete (the fails counter reached its maximum value). Here is the corresponding code snippet :
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
...
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
Since 13 is the key code of ENTER, the above code could be expressed like this : "When ENTER is pressed, and if the game is not over, decide if the player's guess is right or wrong.".
3. A bit of painting
An improvement can be found here : https://stackoverflow.com/a/50085635/1636522. However, the best implementation is here : https://stackoverflow.com/a/50090320/1636522. It replaces sections 3.1 and 3.2, but section 3.3 is still relevant.
So far we have covered around 50% of the source code. We are able to distinguish native and user defined functions, and we have an good overview of the structure and logic of the program. Now it's time to talk about the remaining 50% code, which is related to the output of the program.
Hang on, the tough part is yet to come +0+'
3.1. The data structures
The three data structures I'm going to describe are involved in drawing the gallows. Note that if you want another ASCII art, you only have to change these structures, the program should keep working fine. Also, they are supposed to be "read only", that's why I named them using capital letters, a widespread convention for constants :
Name | Type | Short description
----------------|------------|--------------------------------
HANGMAN | [String] | The ASCII art.
STROKES_COORDS | [[Int]] | Coordinates of the strokes.
DRAWING_STEPS | [Int] | Steps to complete the drawing.
Not much to say about HANGMAN except that it should be seen as a xy-coordinate plane :
x = 0, y = 0
HANGMAN[y] // "+----+"
HANGMAN[y][x] // "+"
STROKES_COORDS contains the coordinates of the strokes that you can find in the HANGMAN plane. As an example, STROKES_COORDS[5] gives [0,0], which points to the first "+". Furthermore, the array is sorted into chronological order. As a consequence, if you print the first six strokes, you get a snapshot of gallows pole (read from bottom to top) :
STROKES_COORDS[5] -> [0,0] -> +
STROKES_COORDS[4] -> [0,1] -> |
STROKES_COORDS[3] -> [0,2] -> |
STROKES_COORDS[2] -> [0,3] -> |
STROKES_COORDS[1] -> [0,4] -> |
STROKES_COORDS[0] -> [0,5] -> |
DRAWING_STEPS can be seen as another level of indirection on top of STROKES_COORDS. This array is also sorted into chronological order and contains the number of strokes to paint after each wrong guess. The following figure illustrates that three fails leads to print six strokes :
DRAWING_STEPS[3] -> 6 -> +
|
|
|
|
|
After DRAWING_STEPS.length - 1 fails, the drawing is complete and the game is over. As a consequence, the maximum amount of wrong guesses depends on DRAWING_STEPS.length :
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
3.2. Drawing the gallows
The drawGallows function takes the amount of wrong guesses at some point of the game, and returns the ongoing drawing in the form of a two dimensional array ([[String]]) :
> | // 3 fails -> 6 strokes
| drawGallows(3)
< | [
| ["+", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "]
| ]
To build the ongoing drawing, drawGallows relies on the data structures described previously. The function first creates an empty canvas, then it loops through the STROKES_COORDS array and fills the blanks with copies of the first n strokes found in HANGMAN. In the next code snippet you can see the copy in action :
> | canvas = HANGMAN.map(
| () => BLANK_ROW.split("")
| );
< | [
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "],
| [" ", " ", " ", " ", " ", " ", " "]
| ]
> | fails = 3;
| n = DRAWING_STEPS[fails]; // 6
| for (i = 0; i < n; i++) {
| x = STROKES_COORDS[i][0];
| y = STROKES_COORDS[i][1];
| canvas[y][x] = HANGMAN[y][x]; // <- copy
| }
| canvas
< | [
| ["+", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "],
| ["|", " ", " ", " ", " ", " ", " "]
| ]
3.3. A drop of glue
As you can see while playing the game, the program does a little more than printing the ASCII art. We can see a message, the letters and placeholders, the floor under the gallows, and the fails counter. These additions come from the outputState function that combines everything and forwards the result to the output function for printing.
Note that output takes an array of string as argument, hence it's necessary to join the columns of the canvas returned by drawGallows. At the same time, the lines are shifted to the right in order to center the gallows horizontally :
> | drawGallows(3).map(
| x => " ".repeat(3) + x.join("")
| )
< | [
| " + ",
| " | ",
| " | ",
| " | ",
| " | ",
| " | "
| ]
That's all.
We are done !
Congratulations and thanks for reading :-) This answer looks more like a blog post but I hope you appreciate anyway. Drop a comment if you need further explanations.
var HANGMAN = [
"+----+"
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
[0,5], [0,4], [0,3], [0,2],
[0,1], [0,0], [1,0], [2,0],
[3,0], [4,0], [5,0], [5,1], [5,2],
[5,3], [4,3], [6,3], [4,4], [6,4]
];
var DRAWING_STEPS = [
0, 2, 4, 6, 8,
11, 13, 16, 18
];
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
var BLANK_ROW = (
" ".repeat(CANVAS_WIDTH)
);
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
var canvas = HANGMAN.map(
() => BLANK_ROW.split("")
);
var n = DRAWING_STEPS[fails];
for (var i = 0; i < n; i++) {
var x = STROKES_COORDS[i][0];
var y = STROKES_COORDS[i][1];
canvas[y][x] = HANGMAN[y][x];
}
return canvas;
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>
I didn't actually understand what you mean but I think you could do something like this
for(i=1; i <= secret_word.length;i++){
let elem = document.createElement("div");
elem.setAttribute("id", i)
document.appendChild(elem);
}
You will create a div for each letter them you can select them individualy.
What follows comes after this answer : https://stackoverflow.com/a/49974142/1636522.
A better implementation can be found here : https://stackoverflow.com/a/50090320/1636522.
In the previous post, section 3.1, "The data structures", I describe three arrays named HANGMAN, STROKES_COORDS and DRAWING_STEPS. I start by telling you that...
[...] if you want another ASCII art, you only have to change these structures, [...]
Good. However, regarding the first version of the program, it can be a tedious task. Imagine you want an extra dash (-). Then, you'll have to insert the new coordinates into STROKES_COORDS, so far so good, but you'll also have to update the coordinates of all subsequent strokes that must be shifted to the right accordingly. And the same applies to DRAWING_STEPS. Boring right ? Now imagine your ASCII art is ten times bigger... +0+'
To address this problem, we can take advantage of the fact that the position of one stroke depends on the position of the previous stroke, and turn absolute positioning into relative positioning. The trick is to use each pair of coordinates as an offset to compute the next one. The following figure is an attempt to illustrate this mechanism (read from bottom to top) :
[+0,-1] -> [0,0] -> +
[+0,-1] -> [0,1] -> |
[+0,-1] -> [0,2] -> |
[+0,-1] -> [0,3] -> |
[+0,-1] -> [0,4] -> |
[+0,+5] -> [0,5] -> |
The next snippet is the corresponding implementation. It links xy, the relative coordinates of the current stroke, with xys[i-1], the offset coordinates of the previous stroke :
STROKES_COORDS.map(function (xy, i, xys) {
return i > 0 && (
xy[0] += xys[i - 1][0],
xy[1] += xys[i - 1][1]
), xy;
})
Thanks to this trick, when you insert new strokes, subsequent strokes update their positions automatically. Here is an example :
var HANGMAN = [
"+---------+" // <- +5 dashes
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
// first stroke
[+0,+5],
// vertical line
[+0,-1], [+0,-1], [+0,-1], [+0,-1], [+0,-1],
// horizontal line
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
// rope and head
[+0,+1], [+0,+1],
// body and arms
[-1,+1], [+1,+0], [+1,+0],
// legs
[-2,+1], [+2,+0]
];
var DRAWING_STEPS = [
+0, // nothing
+2, +2, +2, // vertical line
+3, +4, +3, // horizontal line
+2, +3, +2 // character
];
As you can see, there is a very little difference with the old code :
$ diff a b
2,6c2,6
< "+----+"
< , "| |"
< , "| o"
< , "| /M\\"
< , "| / \\"
---
> "+---------+" // <- +5 dashes
> , "| |"
> , "| o"
> , "| /M\\"
> , "| / \\"
16a17
> [+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
28c29
< +2, +3, // horizontal line
---
> +3, +4, +3, // horizontal line
That's all :-)
var HANGMAN = [
"+----+"
, "| |"
, "| o"
, "| /M\\"
, "| / \\"
, "|"
];
var STROKES_COORDS = [
// first stroke
[+0,+5],
// vertical line
[+0,-1], [+0,-1], [+0,-1], [+0,-1], [+0,-1],
// horizontal line
[+1,+0], [+1,+0], [+1,+0], [+1,+0], [+1,+0],
// rope and head
[+0,+1], [+0,+1],
// body and arms
[-1,+1], [+1,+0], [+1,+0],
// legs
[-2,+1], [+2,+0]
];
var DRAWING_STEPS = [
+0, // nothing
+2, +2, +2, // vertical line
+2, +3, // horizontal line
+2, +3, +2 // character
];
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
var BLANK_ROW = (
" ".repeat(CANVAS_WIDTH)
);
var MAX_FAILS = (
DRAWING_STEPS.length - 1
);
STROKES_COORDS = (
STROKES_COORDS.map(function (xy, i, xys) {
return i > 0 && (
xy[0] += xys[i - 1][0],
xy[1] += xys[i - 1][1]
), xy;
})
);
DRAWING_STEPS = (
DRAWING_STEPS.map(function (x, i, xs) {
return i === 0 ? x : (
xs[i] += xs[i - 1]
);
})
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
var canvas = HANGMAN.map(
() => BLANK_ROW.split("")
);
var n = DRAWING_STEPS[fails];
for (var i = 0; i < n; i++) {
var x = STROKES_COORDS[i][0];
var y = STROKES_COORDS[i][1];
canvas[y][x] = HANGMAN[y][x];
}
return canvas;
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>
What follows comes after this answer : https://stackoverflow.com/a/50085635/1636522.
While I was looking for another ASCII art, I stumbled upon this one :
0000000000000
0 0
0 1
0 1 1
0 1
0 324
0 3 2 4
0 3 2 4
0 5 6
0 5 6
0 5 6
0 5 6
0
0
0
I immediately figured out the idea, which is far smarter than mine... +0+' This is a mask containing the minimum amount of fails required to print each character. Here is what we get regarding our implementation, you should see the drawing behind the numbers :
var HANGMAN_STEPS = [
[3, 4, 4, 5, 5, 5, 0]
// + - - - - +
, [3, 0, 0, 0, 0, 6, 0]
// | |
, [2, 0, 0, 0, 0, 6, 0]
// | o
, [2, 0, 0, 0, 7, 7, 7]
// | / M \
, [1, 0, 0, 0, 8, 0, 8]
// | / \
, [1, 0, 0, 0, 0, 0, 0]
// |
];
This structure contains the information of both STROKES_COORDS and DRAWING_STEPS described previously, what makes it easier to read and easier to change. Moreover, drawGallows becomes smaller. Indeed, since HANGMAN and HANGMAN_STEPS match perfectly, it's not necessary to translate indices anymore :
function drawGallows (fails) {
return HANGMAN_STEPS.map((l, y) => (l.map(
(i, x) => i > fails ? " " : HANGMAN[y][x]
)));
}
Give me a rope please...
var HANGMAN = [
"+----+ "
, "| | "
, "| o "
, "| /M\\"
, "| / \\"
, "| "
];
var HANGMAN_STEPS = [
[3, 4, 4, 5, 5, 5, 0]
, [3, 0, 0, 0, 0, 6, 0]
, [2, 0, 0, 0, 0, 6, 0]
, [2, 0, 0, 0, 7, 7, 7]
, [1, 0, 0, 0, 8, 0, 8]
, [1, 0, 0, 0, 0, 0, 0]
];
var MAX_FAILS = HANGMAN_STEPS.reduce((max, l) => (
l.reduce((max, i) => Math.max(max, i), max)
), 0);
var CANVAS_WIDTH = HANGMAN.reduce(
(a, x) => Math.max(x.length, a), 0
);
onload = function () {
main("save earth");
};
function main (secret) {
var placeholders = "_".repeat(secret.length);
var state = { fails: 0, progress: placeholders.split("") };
var input = document.getElementById("input");
outputState(state, "Let's try!");
input.onkeyup = function (ev) {
if (ev.which === 13) {
var value = this.value;
this.value = ""; // reset input box
if (value === "reset") {
state.fails = 0;
state.progress = placeholders.split("");
outputState(state, "Let's try again!");
} else if (!isGameOver(state)) {
updateState(value, secret, state);
}
}
};
}
function isGameOver (state) {
return state.fails >= MAX_FAILS || (
state.progress.indexOf("_") === -1
);
}
function updateState (input, secret, state) {
if (fillIn(input, state.progress, secret)) {
if (state.progress.indexOf("_") === -1) {
outputState(state, "Good job :-)");
} else {
outputState(state, "Yes! Keep it up :-D");
}
} else {
if (++state.fails === MAX_FAILS) {
outputState(state, "Bad job :-(");
} else {
outputState(state, "No... Hang on :-P");
}
}
}
function fillIn (letter, progress, secret) {
var found = false;
for (var i = 0; i < secret.length; i++) {
if (secret[i] === letter) {
found = true, progress[i] = secret[i];
}
}
return found;
}
function drawGallows (fails) {
return HANGMAN_STEPS.map((l, y) => (l.map(
(i, x) => i > fails ? " " : HANGMAN[y][x]
)));
}
function outputState (state, message) {
output([
message, "",
state.progress.join(" "), ""
].concat(
drawGallows(state.fails).map(
x => " ".repeat(3) + x.join("")
)
).concat((
"-".repeat(CANVAS_WIDTH + 6)
) + " fails = " + (
state.fails + " / " + MAX_FAILS
)));
}
function output (lines) {
var p = document.getElementById("pre");
p.textContent = " " + lines.join("\n ");
}
<table width="100%" cellspacing="0">
<tr>
<td width="40%" valign="top" style="text-align: center;">
<p style="font-size: 14px;">
Type a character or "reset"<br>
(white spaces matter),<br>
then press ENTER.
</p>
<input id="input" type="text">
</td>
<td valign="top" style="border-left: 1px solid #999;">
<pre id="pre" style="
font-size: 12px;
font-family: monospace, monospace;
"></pre>
</td>
</tr>
</table>

Regular Expression doesn't count characters that are part of * quantifier

the regular expression: /([a-z][0-9]*){6,12}/i
so i am expecting this to return true if a string contains more than 6 and less than 12 characters even if there aren't 6 alphabetical characters, but it doesn't, i want "123456789a" to return true and "abcdefghi1", but the first one doesn't.
var myRegEx = /([a-z][0-9]*){6,12}/i;
function checkIt() {
var myString = document.getElementsByTagName("input")[0].value;
if(myRegEx.test(myString) == true) {
document.getElementsByTagName("p")[0].className = "trueOrFalse true";
document.getElementsByTagName("p")[0].innerHTML = "True";
}
else {
document.getElementsByTagName("p")[0].className = "trueOrFalse false";
document.getElementsByTagName("p")[0].innerHTML = "False";
}
}
https://jsfiddle.net/y71mudms/2/
the correct regex is
var myRegEx = /^[0-9]{6,11}[a-z]{1}$/i;
we search exact match of digits + 1 char from 6 to 12
/^[0-9]{6,11}[a-z]{1}$/i;
^ ^ ^ ^
| | | |_ end of string
| | |
| | |_ from 6 min to 11 max repetitions
| |
| |_ digit 0-9 include all digits
|
|_ begin of string
ref. 6 digits regular expression
Just wrap a check for the string-length around your regex-conditions:
if string.length > 6 && string.length < 12) {
// if regex...
}

How to insert new line after N char count in javascript?

I have a string which may have new line '\n' char in it. Now I want to insert new line '\n' after every 4 (or N) chars in that string.
For example:
1)
INPUT: "I am John Doe."
OUTPUT: "I am\nJohn\nDoe"
In above example inserting '\n' after 4 char including space
2)
INPUT: "I\nam John Doe"
OUTPUT: "I\nam J\nohn \nDoe"
In above example inserting space after 4 chars after first '\n' already present in the string
3)
INPUT: 12345\n67890
OUTPUT: 1234\n5\n6789\n0
4)
INPUT: "1234\n56\n78901"
OUTPUT: "1234\n56\n7890\n1"
So far I have created a function which inserts '\n' after every 4 chars but it does not consider '\n' if it is already present in the original string.
function addNewlines(str) {
if (str.length >= 4) {
var result = '';
while (str.length > 0) {
result += str.substring(0, 4) + '\n';
str = str.substring(4);
}
return result;
}
return str;
}
I call this function on every keypress and pass the original string and get output and use it further. I hope you understand what I meant to say here. It should preserve the previously inserted new lines.
Let me know I can explain further. With more examples.
Here is my best guess as to what is being asked for :
function addNewLines (str) {
return str.replace (/(?!$|\n)([^\n]{4}(?!\n))/g, '$1\n');
}
Some test strings and their results :
"I am John Doe.", -> "I am\n Joh\nn Do\ne."
"I\nam John Doe", -> "I\nam J\nohn \nDoe"
"12345\n67890", -> "1234\n5\n6789\n0"
"1234\n56\n78901", -> "1234\n56\n7890\n1"
"ABCD\nEFGH\nIJKL", -> "ABCD\nEFGH\nIJKL\n"
"1234", -> "1234\n"
"12341234" -> "1234\n1234\n"
For those of you for whom regular expressions are mysterious here is a breakdown:
---------------------------- (?! Check that following character(s) are not
| ------------------------- $|\n Beginning of string or a newline character
| | --------------------- )
| | | -------------------- ( Start of capture group 1
| | || ------------------ [^\n] Any single character other than newline
| | || | -------------- {4} Previous element repeated exactly 4 times
| | || | | ----------- (?! Check that following character(s) are not
| | || | | | --------- \n a newline
| | || | | | | ------- )
| | || | | | | |------ ) End of capture group 1
| | || | | | | || ---- /g in replace causes all matches to be processed
| | || | | | | || |
/(?!$|\n)([^\n]{4}(?!\n))/g
function parseInput(str, char, length){
var split = str.split(char),
regex = RegExp('(.{' + length + '})','g');
split[split.length-1] = split[split.length - 1].replace(regex, '$1' + char);
return split.join(char);
}
console.log(parseInput("I am John Doe.", "\n", 4));
// output = "I am\n Joh\nn Do\ne."
Split the string by "\n" str.split("\n"). You get an array of strings.
Do your additional parsing and manipulation checking the element length and putting the result in a new array results.
Join the strings using results.join("\n").
This will remove "\n" duplicates too if you avoid to append or prepend "\n" to results elements.
Here is my code:
function ngram_insert (n, ins, input)
{
var output = "";
var i = 0;
while (i < strlen(input))
{
if (i > 0 && i % n == 0)
{
output += ins;
}
output += input[i];
i++;
}
return output;
}
Test:
var output = ngram_insert (3, "\n", "This is a test.");
function f(n, ins, str) {
if (str.length == 0)
return "";
var i = str.indexOf("\n"), len = str.length, newStr;
if (i == -1) {
i = 1;
newStr = str[0];
}
else {
newStr = str.substring(0, i + 1);
}
var k = 1;
while (k + i < len) {
newStr += str[k + i];
if (k % n == 0) {
newStr += ins;
}
k++;
}
return newStr;
}
Calling f(4, "\n", "I\nam John Doe"); returns "I\nam J\nohn \nDoe"

Categories