console.log("Start file 1 =========================================");
function Letter (letter) {
this.letter = letter;
this.guess = false;
this.answer = function () {
if (!this.guess) {
return "_";
}
else if (this.guess === true) {
return this.letter;
}
}
this.letterTest = function (guessed) {
if (guessed === this.letter) {
this.guess = true;
// this.letter = guessed;
} else {
this.letter = "_";
}
}
};
module.exports = Letter;
console.log("End file 1 =========================================");
console.log("Start file 2 =========================================");
var Letter = require("./letter.js");
function Word (word) {
this.splitWord = [];
for (var i = 0; i < word.length; i++) {
var eachLetter = new Letter (word[i]);
this.splitWord.push(eachLetter);
}
this.stringRep = function () {
var testedWord = [];
for (var i = 0; i < this.splitWord.length; i++) {
testedWord.push(eachLetter.answer());
}
testedWord = testedWord.join(" ");
// console.log(testedWord);
return testedWord;
};
this.eachGuess = function (input) {
for (var i = 0; i < this.splitWord.length; i++) {
this.splitWord[i].letterTest(input);
}
}
}
module.exports = Word;
console.log("End file 2 =========================================");
console.log("Start file 3 =========================================");
var Word = require("./word.js");
var inquirer = require('inquirer');
var remainingGuesses = 10;
var mainGame;
var currentWord;
var liveWord = [];
completeWord = null;
let countryPicker;
let testedWord;
var europe = ["Albania", "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Denmark", "England", "France", "Greece", "Germany",
"Hungary", "Iceland", "Italy", "Lithuania", "Monaco", "Norway", "Poland", "Portugal", "Romania", "Serbia", "Slovakia", "Spain", "Sweden",
"Switzerland", "Ukraine"];
// Function that picks a random country
function pickCountry () {
countryPicker = europe[Math.floor((Math.random() * europe.length) + 1)];
var mainGame2 = new Word (countryPicker);
mainGame = mainGame2;
// Display word
currentWord = mainGame.stringRep();
currentWord = JSON.stringify(currentWord);
console.log("Word: " + currentWord);
};
pickCountry();
// Delete this after
console.log("1: " + countryPicker);
console.log("2: " + currentWord);
inquirer.prompt([
{
type: "input",
name: "game",
message: "Guess a letter!"
}
]).then(function(inquirerResponse) {
liveWord = mainGame.splitWord;
mainGame.eachGuess(inquirerResponse.game);
for (let i = 0; i < liveWord.length; i++) {
console.log(mainGame.splitWord[i].letter);
}
});
I built a hangman game using constructor functions. I have set it up so when a random word is chosen, each letter will be displayed as an underscore.
I used the inquirer package to ask for a letter. When the first letter is guessed correctly it successfully replaces the the underscore with the letter in the liveWord array. The problem is, it only works for one letter. I need to make it work until the full word is guessed. FYI File 1 and 2 are only there for reference, my problem is only in file 3. No need to look at the first 2. Any tips?
There are several issues in your code:
In the letterTest method you set the letter property to underscore when the guess is different from the letter. This is wrong, because then you'll never know again what the correct letter is. Remove this. It is enough to have the right value for the guess property
In the stringRep method you refer to the variable eachLetter in the loop, which has nothing to do there. Instead you should use this.splitWord[i].
There is no loop that allows the user to make a second guess, so it is only normal it only works once. There needs to be a loop that decreases the value of your variable remainingGuesses, which you didn't use so far.
You should not display splitWord. This is related to point 1. Instead you should display stringRep() which takes into account whether or not the letter was already guessed based on the guessed property. And that is exactly what you need to output.
Logic is missing that detects whether the word was found completely. In that case a message would be appropriate and the guessing cycle (which was not implemented) should be interrupted.
To facilitate the looping, I would suggest to use the async/await syntax for dealing with the promise returned by inquirer.
Here is your code with the above-listed points corrected. For the purpose of making it runnable in this snippet widget, I did not split it into modules as you did nor included inquirer (I put a simplified replacement for it inline).
I also did not attempt to make many other improvements, so that you could still recognise your own work. All changes are commented:
function Letter (letter) {
this.letter = letter;
this.guess = false;
this.answer = function () {
if (!this.guess) {
return "_";
}
else { // No need to check whether this.guess is true here. It is the logical consequence...
return this.letter;
}
}
this.letterTest = function (guessed) {
if (guessed === this.letter) {
this.guess = true;
}
// Don't change this.letter, as you will forever forget what the correct letter is!
// (code was deleted from here)
}
}
function Word (word) {
this.splitWord = [];
for (var i = 0; i < word.length; i++) {
var eachLetter = new Letter (word[i]);
this.splitWord.push(eachLetter);
}
this.stringRep = function () {
var testedWord = [];
for (var i = 0; i < this.splitWord.length; i++) {
// Don't push eachLetter, but use the i-variable as index!
testedWord.push(this.splitWord[i].answer());
}
testedWord = testedWord.join(" ");
return testedWord;
}
this.eachGuess = function (input) {
for (var i = 0; i < this.splitWord.length; i++) {
this.splitWord[i].letterTest(input);
}
}
}
// Simplified implementation of inquirer for this snippet only:
var inquirer = {
prompt([{type, name, message}]) {
return new Promise((resolve) => {
const input = document.querySelector(`[name=${name}]`);
input.value = "";
input.placeholder = message;
input.onchange = e => resolve({ [name]: input.value });
});
}
}
var remainingGuesses = 10;
var mainGame;
var currentWord;
var liveWord = [];
completeWord = null;
let countryPicker;
let testedWord;
var europe = ["Albania", "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Denmark", "England", "France", "Greece", "Germany",
"Hungary", "Iceland", "Italy", "Lithuania", "Monaco", "Norway", "Poland", "Portugal", "Romania", "Serbia", "Slovakia", "Spain", "Sweden",
"Switzerland", "Ukraine"];
function pickCountry () {
countryPicker = europe[Math.floor((Math.random() * europe.length) + 1)];
var mainGame2 = new Word (countryPicker);
mainGame = mainGame2;
currentWord = mainGame.stringRep();
currentWord = JSON.stringify(currentWord);
console.log("Word: " + currentWord);
}
pickCountry();
// Delete this after
console.log("1: " + countryPicker);
console.log("2: " + currentWord);
(async function () { // Use an async function to allow the use of AWAIT
while (remainingGuesses--) { // You need a loop to repeat guess/response cycle
// Use AWAIT -- simpler to use than THEN
const inquirerResponse = await inquirer.prompt([{
type: "input",
name: "game",
message: "Guess a letter!"
}]);
const liveWord = mainGame.splitWord;
mainGame.eachGuess(inquirerResponse.game);
// Don't display splitWord here, but stringRep:
const output = mainGame.stringRep();
console.log(output);
// Detect that the word has been found, and exit if so
if (!output.includes("_")) {
console.log("You found it!");
return;
}
}
// The maximum number of guesses was not enough to find the word
console.log('What a pity. You ran out of guesses.');
})();
Letter:
<input name="game">
<button>Guess</button>
I'll not help You with code in Your question, it's annoying to debug, rewrite somebody's code (especially when it's long).
But I'll give You an example:
const words = [
'Azerbaijan', 'America', 'blablabla', 'Argentina', 'lambada', 'Australia', 'schmetterling', 'krankenwagen', 'kugelschreiber'
];
let word, result, charIndexes;
const start = () => {
word = words[parseInt(Math.random()*words.length)];
charIndexes = {};
result = new Array(word.length+1).join('_');
word.split('').forEach((char, i) => {
char = char.toLowerCase();
if (!charIndexes[char]) charIndexes[char] = []
charIndexes[char].push(i);
});
info.innerHTML = '';
output.innerHTML = result;
input.focus();
};
const checkChar = (char) => {
result = result.split('');
if (charIndexes[char]) {
const indexes = charIndexes[char];
indexes.forEach(i => {
result[i] = word.charAt(i);
});
delete charIndexes[char];
}
result = result.join('');
output.innerHTML = result;
if (Object.keys(charIndexes).length === 0) {
info.innerHTML = 'Congratulations!';
}
};
const input = document.getElementById('letter');
const output = document.getElementById('word');
const info = document.getElementById('info');
input.onkeyup = (e) => {
const char = e.key.toLowerCase();
input.value = '';
checkChar(char);
};
start();
<input type="text" id="letter" value="">
<button onclick="start()">reset</button>
<br/><br/>
<div id="word"></div>
<div id="info"></div>
Related
I've been writing a neural network from scratch to learn from.
but since i'm still learning - I want to make sure what I'm writing is actually correct.
I have an array of arrays (a matrix), of cell objects. attached to a 'brain' object which has the following method two methods:
train: function(data)
{
for (let b=0; b< data.length; b++)// for the length of the training data - I.E. we are going assume we are getting many relatively shortly indexed arrays
{
if(data[b].answers.length != data[b].questions.length)
{
console.log("bad data");
return false;
}
for(let c=0;c<data[b].questions.length;c++)
{
brain.attachInputLayer(data[b].questions[c]);
brain.updateForward();
let direction = brain.determinDirection(data[b].answers[c]); //return an array of updateObject with determined weights bias value adjustments, which each cell gets updated order should be from generation by column;
brain.cellMatrix.forEach(cellArray=> cellArray.forEach(cell=> cell.adjust(direction.find(x=> x.ID ===cell.ID))));
brain.updateForward();
brain.displayBrain();
}
}
console.log("all training data done");
alert("win?");
console.log(brain.cellMatrix);
console.log("brain");
}
and
determinDirection:function(answer)
{
// answer is the array of values of each answer cell we want as a result
let arrayOfUpDateObjectsForCell = [];
for(let e=0; e<answer.length; e++)
{
let answerCell = brain.cellMatrix[cellMatrix.length-1][e];
let returnBucket = [];
arrayOfUpDateObjectsForCell.push(answerCell.whatIwant(answer[e], returnBucket));
}
let list = Flat(arrayOfUpDateObjectsForCell);
let realList = Clean(list);
return realList;
}
so each cell of the last generation (the answer output) calls the whatIwant method at brain.train(), this function propagates backwards through the network... but my question really is this:::
:::
does it look like I am calculating the error / direction to move each value correctly?
is averaging the changes between the duplicated updateObjects correct?
(the desiredObjectchange for cell.gen=3,order=0 gets created from each of the next layer cells calling whatIwant. the changes cell.gen=4,order=0 wants cell.gen=3,order=0 to have is averaged with the changes cell.gen=4,order=1 wants for cell.gen=3,order=0).
is averaging the correct operation here?
:::
whatIwant:function(answerValue, returnArray)
{
let desiredWeights = this.weights;
let desiredBias = this.bias;
let desiredActivations = this.activations;
let error = (1/2)*Math.pow(cell.value-answerValue,2);
let desiredObjectChange =
{
ID:this.ID,
weights:this.weights,
bias:this.bias,
activations:this.activations,
value:answerValue,
combine:function(yourCloneFriend)
{
if(yourCloneFriend == false)
{
return;
}
this.bias = (1/2)*(this.bias+yourCloneFriend.bias);
let cWeight = yourCloneFriend.weights[Symbol.iterator]();
let cActivations = yourCloneFriend.activations[Symbol.iterator]();
this.weights.forEach(x=> (1/2)*(x+cWeight.next().value));
this.activations.forEach(y=> (1/2)*(y+cActivations.next().value));
this.recalculateValue();
return this;
},
recalculateValue:function()
{
this.value = Sigmoid(arrayMultiply(this.weights, this.activations)+this.bias);
}
}
for(let k = 0; k< this.weights.length; k++)
{
let lastValue = Sigmoid(arrayMultiply(desiredWeights, desiredActivations)+desiredBias);
let lastError = (1/2)*Math.pow(lastValue-answerValue,2);
for(let l=0;l<3;l++)
{
let currentValue = Sigmoid(arrayMultiply(desiredObjectChange.weights, desiredObjectChange.activations)+desiredObjectChange.bias);
let currentError = (1/2)*Math.pow(currentValue-answerValue,2);
let positiveRange = false;
if(desiredWeights[k] < 0){ positiveRange = true;}
let nudgedWeightArray = NudgeArray(desiredWeights, k, l, positiveRange); //returns a copy array to test, with weight adjusted.
let testWeightChange = Sigmoid(arrayMultiply(nudgedWeightArray,desiredActivations)+desiredBias);
let testWeightError = (1/nudgedWeightArray.length)*Math.pow(testWeightChange - answerValue, 2);
let testWeightResult = compareSmallnumbers('isSmaller', currentError, testWeightError);
if(testWeightResult);
{
desiredWeights = nudgedWeightArray;
currentError = testWeightError;
}
positiveRange=false;
if(desiredBias < 0){positiveRange = true;}
let nudgedBiasVal = this.nudge(desiredBias,l,positiveRange);
let testBiasChange = Sigmoid(nudgedBiasVal+desiredWeights[k]*desiredActivations[k]);
let testBiasError = (1/1)*Math.pow(testBiasChange - answerValue, 2);
let testBiastResult = ('isSmaller', currentError, testBiasError);
if(testBiastResult);
{
desiredBias = nudgedBiasVal;
currentError = testBiasError;
}
positiveRange=!!Math.random(0,1)>5;
let nudgedAcitivationArray = NudgeArray(desiredActivations,k,l,positiveRange);
let testActivationChange = Sigmoid(arrayMultiply(nudgedAcitivationArray,desiredWeights)+desiredBias);
let testActivationError = (1/nudgedAcitivationArray.length)*Math.pow(testActivationChange - answerValue, 2);
let testActivationResult = compareSmallnumbers('isSmaller', currentError, testActivationError);
if(testActivationResult);
{
desiredActivations[k] = nudgedAcitivationArray[k];
currentError = testActivationError;
}
//and the end of the loop, update the error to the new value
let errorResult = compareSmallnumbers('isSmaller',lastError, currentError);
if(errorResult)
{
lastError = currentError;
}
}
desiredObjectChange.weights[k] = desiredWeights[k];
desiredObjectChange.bias = desiredBias;
desiredObjectChange.activations[k] = desiredActivations[k];
desiredObjectChange.value = Sigmoid(arrayMultiply(desiredObjectChange.weights, desiredObjectChange.activations)+desiredObjectChange.bias);
}
let combineObject = returnArray.find(x=>x.ID === desiredObjectChange.ID);
if(!combineObject)
{
returnArray.push(desiredObjectChange);
}
//that was this object - simple stuff, now we need to call this function
if(Array.isArray(cell.lastGenerationTargetKeys) && cell.lastGenerationTargetKeys.length)
{
let nextActivation = desiredObjectChange.activations[Symbol.iterator]();
brain.cellMatrix[cell.generation-1].forEach(x=> x.whatIwant(nextActivation.next().value, returnArray));
return returnArray;
}
else
{
return;
}
},
clean,flat and NudgeArray are these::
function Clean(array)
{
let rArray = [];
array.forEach((x)=>
{
let search = rArray.find(y=>y.ID ===x.ID);
if(search === undefined)
{
rArray.push(x);
}
else
{
rArray[rArray.indexOf(search)].combine(x);
}
});
return rArray;
}
function Flat(array)
{
let holdBucket = [];
let flatten = function(array)
{
for(let i = 0; i<array.length;i++)
{
if(Array.isArray(array[i]))
{
flatten(array[i]);
}
else
{
holdBucket.push(array[i]);
}
}
}
flatten(array);
return holdBucket;
}
function NudgeArray(array ,arrayIndex, Nudgeindex, isPositive)
{//nudge index is designed to act like a variable learning rate modifier, as it tests, jumps decrease in size
let returnArray = [];
array.forEach(x=>returnArray.push(x));
let value = returnArray[arrayIndex];
if(isPositive)
{
value+=(Math.random(0,1)/(Nudgeindex+3));
value = Sigmoid(value);
}
else
{
value+=(Math.random(-1,1)/(Nudgeindex+3));
value = Sigmoid(value);
}
returnArray.splice(arrayIndex,1,value);
return returnArray;
}
I'm trying to come up with some very reusable code that will look up and perform variable substitutions within a string.
The example string below contains a $$ reference to a variable. Format is varname.key.
I want the subText() function to be reusable. The issue I'm having is repvars themselves can require substitution. The code hasn't finished substituting the example text and I'm asking it to substitute the repvars.cr by calling the same function. This seems to through it off. I'm saying that because if I do it separately in works.
var exampleText = "A string of unlimited length with various variable substitutions included $$repvars.cr$$";
var repvars = {
cr: 'Copyright for this is $$repvars.year$$',
year: '2019'
}
function subText(text) {
var subVars = findSubs(text);
return makeSubs(text, subVars);
}
function findSubs(theText) {
var subarr = [];
while (theText.indexOf('$$') > -1) {
theText = theText.substring(theText.indexOf('$$') + 2);
subarr.push(theText.substring(0, theText.indexOf('$$')));
theText = theText.substring(theText.indexOf('$$') + 2);
}
return subarr;
}
function makeSubs(text, subs) {
for (var s = 0; s < subs.length; s++) {
var subst = getSubVal(subs[s]);
text = text.split("$$" + subs[s] + "$$").join(subst);
}
return text;
}
function getSubVal(subvar) {
var subspl = subvar.split('.');
switch (subspl[0]) {
default:
return processRepVar(subspl[1]);
}
}
function processRepVar(rvName) {
var data = getRepVarData(rvName);
if(data.indexOf('$$') > -1) {
subText(data);
} else {
return data;
}
}
function getRepVars() {
return repvars;
}
function getRepVarData(key) {
return getRepVars()[key];
}
subText(exampleText);
Aren't you just missing a return here?
function processRepVar(rvName) {
var data = getRepVarData(rvName);
if(data.indexOf('$$') > -1) {
subText(data);
} else {
return data;
}
}
Changing subText(data) to return subText(data); makes your code work for me.
Working jsfiddle: https://jsfiddle.net/uzxno754/
Have you tried regular expressions for this?
function replace(str, data) {
let re = /\$\$(\w+)\$\$/g;
while (re.test(str))
str = str.replace(re, (_, w) => data[w]);
return str;
}
//
var exampleText = "A string with variables $$cr$$";
var repvars = {
cr: 'Copyright for this is $$year$$',
year: '2019'
}
console.log(replace(exampleText, repvars))
Basically, this repeatedly replaces $$...$$ things in a string until there are no more.
Is there any easy way to parse the following string to array. I can convert array to string but no idea how to convert back to array.
// Input
"Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
}
]
// Input
"(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// Output
[
{
all: ["Keyword1", "Keyword2"],
any: ["Keyword3", "Keyword4"],
not: ["Keyword5", "Keyword6"]
},
{
all: ["Keyword7", "Keyword8"],
any: ["Keyword9", "Keyword10"],
not: ["Keyword11", "Keyword12"]
}
]
First things first:
I don't validate the input. This answer gives you an approach. You should validate the input, especially since you say it comes from the user :)
We will make use of the matchRecursive function from this blog.
This function will help us group the correct parentheses.
var matchRecursive = function () {
var formatParts = /^([\S\s]+?)\.\.\.([\S\s]+)/,
metaChar = /[-[\]{}()*+?.\\^$|,]/g,
escape = function (str) {
return str.replace(metaChar, "\\$&");
};
return function (str, format) {
var p = formatParts.exec(format);
if (!p) throw new Error("format must include start and end tokens separated by '...'");
if (p[1] == p[2]) throw new Error("start and end format tokens cannot be identical");
var opener = p[1],
closer = p[2],
/* Use an optimized regex when opener and closer are one character each */
iterator = new RegExp(format.length == 5 ? "["+escape(opener+closer)+"]" : escape(opener)+"|"+escape(closer), "g"),
results = [],
openTokens, matchStartIndex, match;
do {
openTokens = 0;
while (match = iterator.exec(str)) {
if (match[0] == opener) {
if (!openTokens)
matchStartIndex = iterator.lastIndex;
openTokens++;
} else if (openTokens) {
openTokens--;
if (!openTokens)
results.push(str.slice(matchStartIndex, match.index));
}
}
} while (openTokens && (iterator.lastIndex = matchStartIndex));
return results;
};
}();
Next, this is the algorithm I would use based on the data you provided:
we determine if we have 1st kind of input or 2nd type, by simply checking if str.startsWith("(");
we initialize the followings:
groupedItems for an array that will transform 2nd type of input into 1st type of input, so that we use the same code for both afterwards
returnArr for the returned data
We loop over the groupedItems and prepare an empty keywordObj
In this loop, we determine which are the any keywords by making use of the matchRecursive function and splitting the result after ' OR ' - the resulting items will be any items
For the rest of the keywords (all or not) we need to get to a single word - so we split again, this time after " ", the result of the split being an array of keywords
We loop over the keywords and determine if they are not keywords by checking if they start with -, otherwise we treat them as all keywords.
Here's the code for it:
function output(str){
var groupedItems = [];
if(str.startsWith("(")){
groupedItems = matchRecursive(str,"(...)");
} else {
groupedItems.push(str);
}
var returnArr = [];
for (var i = 0; i<groupedItems.length;i++){
var keywordObj = {all:[], any:[], not: []};
var thisGroup = groupedItems[i];
var arr = matchRecursive(thisGroup, "(...)");
if (arr.length != 1) throw new Error("unexpected input");
keywordObj.any = arr[0].split(" OR ");
var restOfKeywords = thisGroup.split(" (" + arr[0] + ") ");
for (var j = 0; j<restOfKeywords.length; j++){
var keyWords = restOfKeywords[j].split(" ");
for (var k = 0; k<keyWords.length;k++){
if (keyWords[k].startsWith("-"))
keywordObj.not.push(keyWords[k])
else
keywordObj.all.push(keyWords[k])
}
}
returnArr.push(keywordObj);
}
return returnArr;
}
// input "(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)"
// output [{"all":["Keyword1","Keyword2"],"any":["Keyword3","Keyword4"],"not":["-Keyword5","-Keyword6"]},{"all":["Keyword7","Keyword8"],"any":["Keyword9","Keyword10"],"not":["-Keyword11","-Keyword12"]}]
Here is a solution https://codepen.io/anon/pen/NXMoqo?editors=0012
{
// test cases
// const input = 'Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6';
const input = '(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)';
// const input = '((Keyword1 OR Keyword2 OR Keyword3) Keyword4 Keyword6 -Keyword5 -Keyword7) OR (Keyword8 Keyword9 (Keyword10 OR Keyword11) -Keyword12 Keyword13 -Keyword14 -Keyword15)';
const output = [];
input.split(') OR (').forEach(group => {
let trimmedGroup = group.replace(/^\(/, '').replace(/\)$/, '');
let anyGroup = trimmedGroup.match(/\(.+\)/).join('').replace(/[OR\)\(]/g, '').match(/\w+/g);
let notGroup = trimmedGroup.match(/-\w+/g).map(element => element.replace('-', ''));
let allGroup = trimmedGroup.replace(/\(.+\)/g, '').replace(/-\w+/g, '').match(/\w+/g);
output.push({
all: allGroup,
any: anyGroup,
not: notGroup
});
});
console.log(output);
}
can you check this
var arr = [], obj = {any:[], not:[], all: []};
function splitString(str) {
var object = JSON.parse(JSON.stringify(obj));
var strArr = str.split(" ");
var i=0;
while(strArr.length !== 0 && i<10) {
newStr = strArr.splice(0, 1)[0];
if(newStr.indexOf("(") != -1) {
while(newStr.indexOf(")") == -1) {
object.any.push(newStr.replace(")", "").replace("(", ""))
strArr.splice(0, 1);
newStr = strArr.splice(0, 1)[0];
}
object.any.push(newStr.replace(")", ""))
} else if(newStr.indexOf("-") != -1) {
object.not.push(newStr.substring(1).replace(")", ""))
} else {
object.all.push(newStr.replace(")", ""))
}
i++;
}
arr.push(object)
}
function convertToObj(string){
if(string.indexOf(") OR ") !== -1){
string.split(") OR ").forEach(function(str){
splitString(str.substring(1));
});
} else {
splitString(string);
}
}
convertToObj("Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6")
convertToObj("(Keyword1 Keyword2 (Keyword3 OR Keyword4) -Keyword5 -Keyword6) OR (Keyword7 Keyword8 (Keyword9 OR Keyword10) -Keyword11 -Keyword12)")
console.log(arr)
I wrote my code to search string for keywords and extracting needed data, but I have problems when I'm trying to search with keywords in arrays named: sort, title and artist. When I'm doing it I get an error about potential infinite loop.
var type = ['track','tracks','song','songs','album','albums'];
var artist = ['created by', 'made by'];
var genre = ['genre'];
var limit = ['set limit'];
var title = ['title','name'];
var sort = ['sort by', 'classificate by', 'separate by'];
var sortBy = ['popularity'];
// function changeWordsToNumbers(words) {
// if (msg.numbers[words])
// return msg.numbers[words];
// }
function searchForIndex(instruction, keywords) {
for (i = 0; i < keywords.length; i++) {
let search = instruction.search(keywords[i]);
if (search)
return search;
}
return false;
}
function getSearchResult(wanted) {
var searchResult = {
artist : searchForIndex(wanted, artist),
genre : searchForIndex(wanted, genre),
limit : searchForIndex(wanted, limit),
type : searchForIndex(wanted, type),
title : searchForIndex(wanted, title),
sort : searchForIndex(wanted, sort),
sortBy : searchForIndex(wanted, sortBy)
};
return searchResult;
}
function removeJunkKeyword(searchResult,instruction) {
for(var property in searchResult) {
if(searchResult.hasOwnProperty(property)) {
if(searchResult[property] != - 1) {
instruction = instruction.slice(0, searchResult[property] - 1);
}
}
}
return instruction;
}
function checkExist(searchResult) {
for(var property in searchResult) {
if(searchResult.hasOwnProperty(property)) {
if(searchResult[property] != -1)
return false;
}
}
return true;
}
function findAndCleanQuery(instruction, keywords) {
var exist = instruction.search(keywords);
var result = instruction.slice(exist + keywords.length + 1, instruction.length);
var searchResult = getSearchResult(result);
if (exist != -1) {
if (checkExist(searchResult)) {
return result;
} else {
result = removeJunkKeyword(searchResult,result);
return result;
}
}
return false;
}
function searchFor(instruction, keywords) {
for (i = 0; i < keywords.length; i++) {
let result = findAndCleanQuery(instruction,keywords[i]);
if (result)
return result;
}
return false;
}
function searchForType(instruction) {
for (i = 0; i < type.length; i++) {
let search = instruction.search(type[i])
if(search)
return type[i];
}
return false;
}
function searchForKeywords(instruction) {
msg.artist = searchFor(instruction, artist);
msg.type = searchForType(instruction, type);
msg.genre = searchFor(instruction, genre);
msg.limit = searchFor(instruction, limit);
msg.title = searchFor(instruction, title);
msg.sort = searchFor(instruction, sortreg);
}
var msg = {}
msg.instruction = 'Search for me';
searchForKeywords(msg.instruction);
console.log(msg.artist);
console.log(msg.type);
console.log(msg.genre);
console.log(msg.limit);
console.log(msg.title);
console.log(msg.sort);
Link for code: https://repl.it/J4Mc/9
PS. The object msg is used by node-red to communicate between nodes.
The issue is that you're doing this on several of your loops:
for (i = 0; i < keywords.length; i++) {
...where you should be doing this instead:
for (let i = 0; i < keywords.length; i++) {
Without using let, the variable i is effectively global. Each time you went into a new loop it got reset to 0, so it was never able to increase, which created the infinite loop.
As a side note, you'll also notice sortreg is undefined when it's used on line 98.
I'm trying to search through a list of multiple values.
Here is the an example of the values:
[
{
"color":"blue",
"medium":"Sculpture",
"place":"Garage"
}
{
"color":"red",
"medium":"Painting",
"place":"Pool"
}
]
Below is my code. Works great to find a single value. But I need to find multiple values. For example I need to look and find the results for queries such as: "red blue" or "blue Painting".
It should return results that have both word.
I don't really know how to solve this, does anybody have an idea?
Thanks a lot
function search(){
var search = $('#search').val();
if(search.length < 1) {
return null;
};
var searches = search.split(" ");
var fields = ["color","medium","place"];
var results = [];
$.each(searches, function(i, word){
var wordResult = searchInJson(word,fields,json);
if( wordResult.length > 0 ) {
results.push(wordResult);
}
});
var results = searchInJson(searches,fields,json);
displaySearchResults(results);
};
function searchInJson(search,fields,json) {
var regex = new RegExp(search);
var results = [];
$.each(json, function(i, image){
$.each(fields, function(j, fieldname){
var field = image[fieldname];
if (regex.test(field)) {
results.push( image );
}
});
});
return results;
}
Here's a quick method to try:
var list = [
{
"color":"blue",
"medium":"Sculpture",
"place":"Garage"
},
{
"color":"red",
"medium":"Painting",
"place":"Pool"
}
];
var search = "red painting";
var results = list.filter(function (el) {
var s = search.toLowerCase().split(" ");
for (var key in el) {
for (var i=0; i < s.length; i++) {
if (el[key].toLowerCase() == s[i]) { // this could use indexOf depending on if you want to match partial words
s.splice(i,1);
i--;
if (!s.length) return true;
}
}
}
return false;
});
console.log(results);