javascript match only certain letters in array - javascript

I'm using the below in a javascript Q & A chatbot. To answer for example "what is AG in the periodic table? Answer is Silver.
if ((input.search("(what is|what's)") != -1) && (input.search("(periodic table)") != -1)) {
document.result.result.value = "Hmmmm, I don't know. Try Google!";
for (i = 0; i < Periodic_Tables.length; i++) {
Periodic_Table = Periodic_Tables[i].split('=');
if (input.indexOf(Periodic_Table[0]) != -1) {
document.result.result.value = Periodic_Table[1];
}
}
return true;
}
Then I have in another file the array laid out like this:
Periodic_Tables=new Array(
"h=Hydrogen",
"he=Helium",
"li=Lithium",
"be=Beryllium",
"b=Boron",
"c=Carbon",
"n=Nitro­gen",
"o=Oxygen",
"f=Fluorine",
"ne=Neon",
"na=Sodium",
"mg=Magnesium",
"ag=Silver"
);
My problem is because the table symbols are only 1 or 2 letters it's matching a lot of wrong things. How can I set this up where "only" b matches boron, be matches beryllium. etc I've looked a word boundaries but can seem to figure out how to use them here.

Instead of this code block which is checking if input contains a symbol:
if (input.indexOf(Periodic_Table[0]) != -1) {
document.result.result.value = Periodic_Table[1];
}
You should check for equality like this:
Periodic_Tables=new Array("h=Hydrogen",
"he=Helium", "li=Lithium", "be=Beryllium", "b=Boron", "c=Carbon", "o=Oxygen",
"f=Fluorine", "ne=Neon", "na=Sodium", "mg=Magnesium", "ag=Silver");
function Parse(input) {
input=input.toLowerCase();
input=input.replace(/[!|?|,|.]/g,"");
if (input.search(/\bu\b/)!=-1) input=input.replace(/\bu\b/,"you");
if (input.search(/\br\b/)!=-1) input=input.replace(/\br\b/,"are");
if (input.search(/\bk\b/)!=-1) input=input.replace(/\bk\b/,"ok");
if (input.search(/\by\b/)!=-1) input=input.replace(/\by\b/,"why");
var words=input.split(" ");
var result = "Hmmmm, I don't know. Try Google!";
if ((input.search("(what is|what's)") != -1) && (input.search("(periodic table)") != -1)) {
for (var w=0; w<words.length; w++) {
for (i=0; i<Periodic_Tables.length; i++) {
Periodic_Table = Periodic_Tables[i].split('=');
if (words[w] == Periodic_Table[0]) {
result = Periodic_Table[1];
return result;
}
}
}
}
return result;
}
alert(Parse("what is h in periodic table"));
DEMO: http://jsfiddle.net/MnyFP/1/

First i'd use 2d array to store your periodic tables, so that you don't have to string split every time you want to use it.
Instead of
Periodic_Tables=new Array(
"h=Hydrogen",
"he=Helium",
"li=Lithium",
"be=Beryllium",
"b=Boron",
"c=Carbon",
"n=Nitro­gen",
"o=Oxygen",
"f=Fluorine",
"ne=Neon",
"na=Sodium",
"mg=Magnesium",
"ag=Silver",
);
Use
Periodic_Tables = [
["h", "Hydrogen"],
["he", "Helium"],
...
]
Assuming that the question is well formatted, that the symbol "AG" has a space in front and after it. I think you could simple test the input against " AG ", or " ag ", if you make it case insensitive. Including the spaces in the test string will for it to find matches that is a word in it self, instead of part of another word.
Pretty use regex has similar abilities, but i am not sure how to do it with regex..

assuming that the question in the chat box ends with the name of the element, u can split the string at the punctuations.(lets say user enters, what is,ag)
function abc(str)
{
String[] parts = str.split("\\W+");
var len=parts.length();
String sub=parts[len-1];
var re=new RegExp("^"+sub+"$","i");
and then use a loop and check the condition
if(re.test(arr[i])){
document.write(arr[i]);
break;
}
}

I would use an array of objects:
Periodic_Tables = [
{Symbol: "h", Element: "Hydrogen"},
{Symbol: "he", Element: "Helium"}
...
]
Then your loop looks like this:
for (i = 0; i < Periodic_Table.length; i++) {
if (input.indexOf(Periodic_Table[i].Symbol) !== -1) {
document.result.result.value = Periodic_Table[i].Element;
}
}
This prevents having to use a regex or a 2d array, and is a little more readable.

I can't seem to get anything to work within the Q and A bot. So I put up a demo here:
http://www.frontiernet.net/~wcowart/aademo.html
Or here is the code: I tried many of the various answers presented. Maybe I'm not implementing them right.
<HTML>
<HEAD>
<TITLE>ChatterBot Page</TITLE>
<script language="JavaScript">
Periodic_Tables=new Array(
"h=Hydrogen",
"he=Helium",
"li=Lithium",
"be=Beryllium",
"b=Boron",
"c=Carbon",
"n=Nitro­gen",
"o=Oxygen",
"f=Fluorine",
"ne=Neon",
"na=Sodium",
"mg=Magnesium",
"ag=Silver"
);
var message = new Array();
var randomnum;
var flagrandom;
function Parse() {
var input = new String(document.chat.input.value);
document.chat.input.value="";
input=input.toLowerCase();
word=input.split(" ");
num_of_words=word.length;
input=input.replace(/[!|?|,|.]/g,"");
word=input.split(" ");
if (input.search(/\bu\b/)!=-1) input=input.replace(/\bu\b/,"you");
if (input.search(/\br\b/)!=-1) input=input.replace(/\br\b/,"are");
if (input.search(/\bk\b/)!=-1) input=input.replace(/\bk\b/,"ok");
if (input.search(/\by\b/)!=-1) input=input.replace(/\by\b/,"why");
if ((input.search("(what is|what's)") != -1) && (input.search("(periodic table)") != -1)) {
document.result.result.value = "Hmmmm, I don't know. Try Google!";
for (var i = 0, len = Periodic_Tables.length; i < len; i++) {
if (Periodic_Tables[i].match('^'+input+'=')) {
document.result.result.value = Periodic_Tables[i].split('=')[1] }
}
return true;}
if (!flagrandom) {
randomnum = [Math.floor(Math.random()*3)]
flagrandom=true;}
message[0] = "Sorry, you stumped me on that one.";
message[1] = "Sorry, a search of my data base comes up empty.";
message[2] = "Not sure";
document.result.result.value = message[randomnum];
randomnum++
if (randomnum>2){randomnum=0}
return true;}
</script>
</head>
<BODY BACKGROUND="FFFFFF" TEXT="#0000cc" LINK="#FFCOOO" ALINK="#FFCC99"
VLINK="#FFC000" marginwidth="0" leftmargin="0" topmargin="0" rightmargin="0">
<Center>
<font size="+3">
ChatterBot
</font>
<br>
<img src="botpix.jpg" border="0" WIDTH="200" HEIGHT="200">
<br>
<form name="result">
<textarea rows=5 cols=40 input type="text" name="result">
</textarea><br>
</form>
</center>
<form name="chat" onSubmit="Parse();return false">
<b>Type here:</b>
<input type="text" name="input" size="100">
</form>
</body>
</html>

Related

Search/filter for an array

I am making a search function for an array. I have a input[text] where for example I put 'ban', then I need all results that start with 'ban' to show up, for example banana, banana milkshake, banana(fried), etc.
How would I go about doing this? I tried, but every time I try it isn't accurate. What I tried is below.
What I have:
var inputBox = document.getElementById('ingredient');
var ingredienten = ["Appel", "Aardbei", "Aardappelen", "Banaan", "Bananen", "Banana"]
inputBox.onkeydown = function(evt) {
$("#autocomplete").empty();
// INSERT CODE FOR SEARCH FUNCTION
}
I had one that came very close, however when I typed 'ban' it came up with 'Aardbei'. Which is obviously wrong. Here it is, maybe I overlooked something?
var inputBox = document.getElementById('ingredient');
var ingredienten = ["banaan", "bananen", "baan", "banana", "baaanana"];
inputBox.onkeydown = function(evt) {
$("#autocomplete").empty();
var input, filter, a, i;
input = document.getElementById("myInput");
filter = inputBox.value.toUpperCase();
for (i = 0; i < ingredienten.length; i++) {
a = ingredienten[i];
if (a.toUpperCase().indexOf(filter) > -1) {
//console.log(a);
$("#autocomplete").append("<li>" + a + "</li>");
} else {
}
}
I think you should use the keyup event instead and you can make use of a regex and the filter function on the array of items:
var inputBox = document.getElementById('ingredient');
var ingredienten = ["Appel", "Aardbei", "Aardappelen", "Banaan", "Bananen", "Banana"]
inputBox.onkeyup = function(evt) {
$("#autocomplete").empty();
var query = $('#ingredient').val();
// escape regex
query = query.replace(
/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"
);
var queryRegExp = new RegExp('^' + query, 'i');
var results = ingredienten.filter(function(item) {
return queryRegExp.test(item);
});
results.forEach(function(item) {
$("#autocomplete").append("<li>" + item + "</li>");
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="ingredient" />
<div id="autocomplete"></div>
Using jQuery UI autocomplete this task can be done very easily:
$('#ingredient').autocomplete({
source: ["Appel", "Aardbei", "Aardappelen", "Banaan", "Bananen", "Banana"]
});
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<input id="ingredient">
Going under the instructions, you can use a regular expression filter here on your array.
const results = ingredienten.filter(item => item.match(/^ban/)); //add i at the end to ignore case
This will iterate the array and return all the results that match the regex "starts with 'ban'".
You can also do a 0-2 substring match == 'ban' but that's a bit more manual.

How to inject a number into HTML from a list?

What is the most convenient way of injecting a number into the HTML of the site (using Chrome Extensions), when the given parameter is found in the website's code? For example we have a list:
www.newsweek.com, hf-title, 2
www.aaa.com, yzs, 1
www.ccc.com, abc, 123
When we find "hf-title" on the website www.newseek.com then number "2" is inserted next to the found paragraph on the website in the browser. When we find "abc" in the code of the website www.ccc.com then number "123" is inserted next to the table, and so on.
There cannot be any connection to the database, just javascript.
The list that is going to be used will be hundreds of rows long, so it is really problematic to use switch statement.
The source table has to be located in the Google Chrome extension files on the PC. The information should be looked for when (or shortly after) the site is being opened.
Example of the source code:
<h2 class="hf-title">
Four NATO Allies Deny Ukraine<span class="overlay article-overlay"></span>
</h2>
<div class="hf-summary">
NATO officials have previously said... </div>
</div>
We add simply
<a> 2 </a>
at the end.
Any ideas? ;)
What you will likely need to do is find all of the text nodes on the page. From there you can begin editing them. The 'modifyTextNodes' function is an example of using a TreeWalker to do this. It is a very efficient method for traversing the DOM.
var arr = [{url:"www.newsweek.com", string:"hf-title", value:"2"},
{url:"www.aaa.com", string:"yzs", value:"1"},
{url:"www.ccc.com", string:"abc", value:"123"}];
function modifyTextNodes() {
var el = document.getElementsByTagName('html')[0];
var walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
while(n = walk.nextNode()) {
modifyNode(n);
}
}
function modifyNode(node) {
if (node.nodeType == Node.TEXT_NODE && node.parentNode != undefined && (val = node.nodeValue.trim())) {
var addToEnd = "";
for (var i=0; i<arr.length; i++) {
if (document.baseURI.indexOf(arr[i].url) > -1 && val.indexOf(arr[i].string) > -1) {
addToEnd += arr[i].value;
}
}
}
if (addToEnd) {
node.nodeValue += addToEnd;
}
}
Alternatively, if it is elements that you are trying to find, you could use querySelectorAll to find all the matching elements.
document.querySelectorAll("[class='" + arr[i].string + "']");
In this case 'modifyAllNodes' would look like
function modifyAllNodes() {
for (var i = 0; i<arr.length; i++) {
if (document.baseURI.indexOf(arr[i].url) > -1) {
var nodes = document.querySelectorAll("[class='" + arr[i].string + "']");
modifyNodes(nodes, arr[i]);
}
}
}
function modifyNodes(nodes, arrEl) {
for (var i=0; i<nodes.length; i++) {
if (node.nodeValue.indexOf(arrEl.string) > -1) {
node.nodeValue += arrEl.value;
}
}
}
first you have to know the structure of the list you are trying to "hack", which means the ID or class names. Afterwards, in your JS check each record of that list if its content matches the string you pass to and then do a .append()

Smart text replacing with jQuery

I need to replace some part of text, e.g. mustache var {{myvar}}, on already loaded page.
Example html:
<html>
<head>
<title>{{MYTITLE}}</title>
</head>
<body>
<p><strong><ul><li>text {{TEXT}}</li></ul></strong></p>
{{ANOTHER}}
</body>
</html>
What's the problem? Use $(html).html(myrenderscript($(html).html()))!
It's ugly, slow and brokes <script> tags.
What do you want?
I want to get closest tag with {{}} and than render and replace.
Your researches?
Firstly, i tried: $('html :contains("{{")). But it returns <title>, <p>, <strong> .... But i need <title> and <li>.
Than i tried to filter them:
$('html :contains("{{")').filter(function (i) {
return $(this).find(':contains("{{")').length === 0
});
...but it WONT return {{ANOTHER}}. And that is my dead end. Your suggestions?
Using http://benalman.com/projects/jquery-replacetext-plugin/ you could do the following:
$('html *').replaceText(/{{([^}]+)}}/, function(fullMatch, key) {
return key;
}, true);
See http://jsfiddle.net/4nvNy/
If all you want to do is replace that text - then surely the following works (or have I mis-understood)
usage is as follows: CONTAINER (body) - replaceTExt (search term (I have built the function to always include {{}} around the term), (replace - this will remove the {{}} as well)
$('body').replaceText("MYTITLE","WHATEVER YOU WANT IT REPLACING WITH");
$.fn.replaceText = function(search, replace, text_only) {
return this.each(function(){
var v1, v2, rem = [];
$(this).find("*").andSelf().contents().each(function(){
if(this.nodeType === 3) {
v1 = this.nodeValue;
v2 = v1.replace("{{" + search + "}}", replace );
if(v1!=v2) {
if(!text_only && /<.*>/.test(v2)) {
$(this).before( v2 );
rem.push(this);
}
else this.nodeValue = v2;
}
}
});
if(rem.length) $(rem).remove();
});
};
You could avoid jQuery altogether if you wanted to with something like this:
<body>
<p><strong>
<ul>
<li>text {{TEXT}}</li>
</ul>
</strong></p>
{{ANOTHER}}
<hr/>
<div id="showResult"></div>
<script>
var body = document.getElementsByTagName('body')[0].innerHTML;
var startIdx = 0, endIdx = 0, replaceArray = [];
var scriptPos = body.indexOf('<script');
while (startIdx != 1) {
startIdx = body.indexOf('{{', endIdx) + 2;
if(startIdx > scriptPos){
break;
}
endIdx = body.indexOf('}}', startIdx);
var keyText = body.substring(startIdx, endIdx);
replaceArray.push({"keyText": keyText, 'startIdx': startIdx, 'endIdx': endIdx});
}
document.getElementById("showResult").innerHTML = JSON.stringify(replaceArray);
</script>
</body>
You can then do what you want with the replaceArray.

Hiding a div element with javascript

Following is the code where I display matched user input in the div but I want to hide the div when there is no match for user input. I can't seem to do it with the following code:
HTML code:
<input id="filter" type="text" placeholder="Enter your filter text here.." onkeyup = "test()" />
<div id="lc"> <p id='placeholder'> </p> </div>
JS code:
// JavaScript Document
s1= new String()
s2= new String()
var myArray = new Array();
myArray[0] = "Football";
myArray[1] = "Baseball";
myArray[2] = "Cricket";
myArray[3] = "Hockey";
myArray[4] = "Basketball";
myArray[5] = "Shooting";
function test()
{
s1 = document.getElementById('filter').value;
var myRegex = new RegExp((s1),"ig");
arraysearch(myRegex);
}
function arraysearch(myRegex)
{
document.getElementById('placeholder').innerHTML="";
for(i=0; i<myArray.length; i++)
{
if (myArray[i].match(myRegex))
{
document.getElementById('lc').style.visibility='visible';
document.getElementById('placeholder').innerHTML += myArray[i] + "<br/>";
}
else
{
document.getElementById('lc').style.visibility='hidden';
}
}
}
Regular expressions are a powerful tool but using them for so trivial a job is often troublesome.First you are using a direct input as regular expression which is never so good.
I copied your code and analyzed the logic you are making many many errors
for(i=0; i<myArray.length; i++)
{
if (myArray[i].match(myRegex))
{
document.getElementById('lc').style.visibility='visible';
document.getElementById('placeholder').innerHTML += myArray[i] + "<br/>";
}
else
{
document.getElementById('lc').style.visibility='hidden';
}
consider your code above, if I enter football, it matches with football, and football is shown. Next it checks for baseball which does not match and visibility changes to hidden!!
Better logic
1.Check what strings match, and add them to the division.
2.Check how many strings have matched, if none, change visibility to hidden.
You are using regular expressions when this actully can be achieved easily with indexOf();
these are pure logical errors
consider using jquery. (with a little http://underscorejs.org/ for utility)
var myArray = ["Football", "Baseball", "Cricket","Hockey", "Basketball", "Shooting"]
$("#filter").keyup(function() {
if(_.include(myArray, $(this).val()) {
$('#lc').show()
} else {
$('#lc').hide()
}
}

<textarea> what key was pressed with javascript

I would like to ask somebody how i can determine what key was pressed in a textarea....
need to write a little javascript code.. a user type in a textarea and i need to write it in a while he writing so the keydown, keypress event handle this functionality, also need to change the text color if a user typed a "watched" word (or the word what he wrote contains the "watched" word/words ) in the textarea.. any idea how i can handle it ??
till now did the text is appear in the <div>, but with this i have a problem.. can't check if the text is in the "watched"... the document.getElementById('IDOFTHETEXTAREATAG'); on keypress is not really works because i got back the whole text inside of the textarea.....
So how i can do it ? any ideas ??? "(Pref. in Mozilla FireFox)
Well, if you were using jQuery, you could do this given that the id of your textarea was 'ta':
$('#ta').keypress(function (evt) {
var $myTextArea = $(this); // encapsulates the textarea in the jQuery object
var fullText = $myTextArea.val(); // here is the full text of the textarea
if (/* do your matching on the full text here */) {
$myTextArea.css('color', 'red'); // changes the textarea font color to red
}
};
I suggest you use the 'onkeyup' event.
$( element ).keyup( function( evt ) {
var keyPressed = evt.keyCode;
//...
});
I have this made like this (plain JS, no JQuery):
function keyDown(e) {
var evt=(e)?e:(window.event)?window.event:null;
if(evt){
if (window.event.srcElement.tagName != 'TEXTAREA') {
var key=(evt.charCode)?evt.charCode: ((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
}
}
}
document.onkeydown=keyDown;
This script is in head tag. I am catching this in all textarea tags. Modify it for your purpose.
2 textareas.
In the first textarea I need to write the words or chars what you want to "watch" in the typing text.
In the second textarea I need to type text, so when I type text, under the textarea need to write what is in the textarea (real time) and highlight the whole word if contains the watched words or chars.
For example:
watched: text locker p
text: lockerroom (need to highlite the whole word because it contains the locker word) or apple (contains the p)
who I can do if a word not start with watched word/char to highlite the whole word?
JavaScript:
var text;
var value;
var myArray;
var found = new Boolean(false);
function getWatchedWords()
{
myArray = new Array();
text = document.getElementById('watched');
value = text.value;
myArray = value.split(" ");
for (var i = 0;i < myArray.length; i++)
{
document.getElementById('writewatched').innerHTML += myArray[i] + "<newline>";
}
}
function checkTypeing()
{
var text2 = document.getElementById('typeing');
var value2 = text2.value;
var last = new Array();
last = value2.split(" ");
if (last[last.length-1] == "")
{
if(found)
{
document.getElementById('writetyped').innerHTML += "</span>";
document.getElementById('writetyped').innerHTML += " ";
}
else
document.getElementById('writetyped').innerHTML += " ";
}
else
check(last[last.length-1]);
}
function check(string)
{
for (var i = 0; i < myArray.length; i++)
{
var occur = string.match(myArray[i]);
if(occur != null && occur.length > 0)
{
if (!found)
{
found = true;
document.getElementById('writetyped').innerHTML += "<span style='color: blue;'>";
}
else
{
found = true;
}
}
else
{
}
}
if(found)
{
document.getElementById('writetyped').innerHTML += string;
}
else
{
document.getElementById('writetyped').innerHTML += string;
}
}
HTML:
<html>
<head>
<title>TextEditor</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<script src='script.js' type='text/javascript'></script>
</head>
<body>
<div>
<p>Watched words:</p>
<textarea id="watched" onblur=getWatchedWords();>
</textarea>
</div>
<div id="writewatched">
</div>
<div>
<p>Text:</p>
<textarea id="typeing" onkeyup=checkTypeing();>
</textarea>
</div>
<div id="writetyped">
</div>
</body>
</html>

Categories

Resources