I'm a novice when it comes to Javascript.
I would like to improve the search in the script provided below.
I have the following code and currently when I type the phrase 'blue widgets' in search, it will only identify/find the checkbox if the phrase 'blue widgets' exits in sequence. For example, If I have a keyword phrase or sentence that contains 'blue cool widgets' and I search for 'blue widgets' it is unable to locate that even though blue and widgets both exist in my keyword phrase.
Could it be possible that if I search for a phrase with 2 or even 3 words in it, then it can find any keyword phrase/sentence on my page in which all words of my search phrase exist and then check the box (which the code already does). The only condition is that all the words of my search phrase have to exist in a sentence/string ?
I would very much appreciate if this solution can be found.
<html>
<head>
<script type="text/javascript">
function checkForWord( wordField )
{
var form = wordField.form;
var word = wordField.value.replace(/^\s+/,"").replace(/\s+$/,"").toLowerCase();
var inputs = form.getElementsByTagName("input");
for ( var e = 0; e < inputs.length; ++e )
{
var field = inputs[e];
if ( field.type == "checkbox" )
{
if ( field.value.toLowerCase().indexOf(word) >= 0 )
{
field.checked = true;
} else {
// OPTIONAL, if you do NOTwant to clear previously checked boxes, omit next line:
field.checked = false;
}
}
}
}
</script>
</head>
<body>
<form onsubmit="return false;">
Type a word: <input name="word" onchange="checkForWord(this);" />
<hr>
<label>
<input type="checkbox" name="keywords" value="This is an example sentence with blue and cool widgets not in order and my current script will not find it.
</label></br/>
<label>
<input type="checkbox" name="keywords" value="This sentence will be found if I search for blue widgets because its in this sentence">
All work and no play makes Jack
</label></br/>
<label>
<input type="checkbox" name="keywords" value="I would like for it to be able to find this sentence also since blue and widgets both words exist but are out of order.
</label></br/>
</form>
</body>
</html>
It would be the best to tokenize your search string (split it by words), execute each search independently (for every word) and then merge results.
/(?=.*blue)(?=.*widgets)/.test( phrase );
(?=...) is a look-ahead, meaning it only matches if the expression is matched somewhere further in the string. The nice part is that it doesn't consume the match, so the above will only match if you have "blue" and "widgets" at some point later in the string, but order doesn't matter.
Feel free to modify those to wrap with whitespace if necessary so that it only matches the entire word (e.g. wrap the words with \b)
To generate that regex dynamically:
var words = 'blue widgets';
new RegExp( '(?=.*' + words.split( /\W+/g ).join( ')(?=.*' ) + ')', 'i' )
Related
I have the following code which works fine for english but not working for arabic. how can i use this code for arabic also. how can I serach it as a string
function highlightSearch() {
var text = document.getElementById("query").value;
var query = new RegExp("(\\b" + text + "\\b)", "gim");
var e = document.getElementById("nav-5-3-primary-ver").innerHTML;
var enew = e.replace(/(<h6>|<\/h6>)/igm, "");
document.getElementById("nav-5-3-primary-ver").innerHTML = enew;
var newe = enew.replace(query, "<h6>$1</h6>");
document.getElementById("nav-5-3-primary-ver").innerHTML = newe;
}
#nav-5-3-primary-ver h6{
background-color:#FF9;
color:#555;
}
<input name="query" id="query" type="text" size="30" maxlength="30">
<input name="searchit" type="button" value="Search" onClick="highlightSearch()">
<div id="nav-5-3-primary-ver">
hello i am this
</br>
اذا كان الجهاز خارج التغطية هل يتم تسجيل البيانات للسيارة؟
</div>
There's a gotcha with \b (in javascript at least) : the notion of "word" it uses (to detect word boundaries) is :
sequences of characters in the set [a-zA-Z0-9_] (latin alphanumerics, plus the _ char)
It won't work as you expect for other charsets (note : even latin diacritics - letters with accents or signs on them - don't work).
Choose some other way to chek that you matched a complete word :
as suggested in this answer : you can write a predicate that matches "a space character or ^ or $"
or match the word without boundaries, and for each match, inspect the characters prior and next to that match
Links to ECMAscript specifications :
Assertions in Regular Expressions
Word Character definition
I currently have a search feature setup that will breakdown the words you've searched and will then check to see if those words exists in a specific div. If they do it will clone those divs and list them inside another div called .search-results. This is currently working well, however I would like to fine tune it with the following:
Be able to make it so the search isn't case sensitive. For example if I search 'apples' or 'APPLES' it will still know to clone the div with the word 'Apples' in.
The cloned divs that have the most words matching from that of the searched sentence to be placed at the top of the .search-results class, this is just so those elements take precedence over the others that are still containing searched words but perhaps slightly less.
So an example would be if I searched 'Lemon Pineapple Orange' I would only expect two results to appear that are:
<div class="box">Lemon Mango Orange</div>
<div class="box">Cherries Pineapple Strawberries Crabapple</div>
and it would be in that order because 'Lemon' and 'Orange' are both part of the same div containing two searched words and therefore goes at the top where as the div containing the word Lemon only has one searched word so would go underneath. I hope that makes sense :-)
I hope that all makes sense. Any help would be great. Below is an example of the code which is working well, but like I said I just want to fine tune it. Many thanks.
$("#search-submit").on("click", function() {
var search = $("#search-input").val();
if (search !== "") {
var searchArray = search.split(" ");
searchArray.forEach(function(searchWord) {
$(".box").each(function() {
if ($(this).is(":contains(" + searchWord + ")")) {
$(this).clone(true).appendTo(".search-results");
}
});
});
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
<input id="search-input" type="text" />
<input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>
In the first code block you have an example of how you can create (or adapt existing) a jQuery selector. In this case :containsInsensitiveWithCount that will act like contains in mode case insensitive and add a data-matches attribute with the number of matches.
Then you can sort based on this attribute.
Note that you might have a problem when you search multiple terms, you'll notice that your code creates a clone for each match, so it duplicates a result if it matches different terms. I have not addressed this here.
EDIT: while I was writing, you edited the question exactly about the note I added. Here is a possible solution:
now the custom selector can accept multiple parameters separated by , (it means you can't search a coma now, if problematic, choose another separator)
the selector loops automatically on the arguments so the count now reflects the total search and avoids duplicates
fixed the sorting (actually with the help of #RoryMcCrossan, I had forgotten the .find(".box"))
call to the selector simplified, you don't need to do each on the ".box", just use $(".box:contains...").clone
//custom jQuery selector - has to be done only once, at the start of the scripts
$(document).ready(function() {
$.expr[":"].containsInsensitiveWithCount = $.expr.createPseudo(function(arg) {
return function( elem ) {
var searchArray = arg.split(",");
var count = 0;
searchArray.forEach(function(searchWord) {
//to match the word exactly: this uses a regexp that searches the word detected between either non-word char or start of string and either non-word char or end of the string. If there are matches, result is an array with the matches. 'g' is for global and 'i' for case-insensitive
var reg = new RegExp('(\\W|^)' + searchWord + '(?=\\W|$)', 'gi');
var match = $(elem).text().match(reg);
if(match){
count += match.length;
}
//to match part of the word: works by splitting the text at the searchWord, if it is found, an array of length (number of occurences + 1) is returned, or else an array with original string (length 1)
//count += $(elem).text().toUpperCase().split(searchWord.toUpperCase()).length - 1;
});
$(elem).attr("data-matches", count);
return count > 0;
};
});
});
$("#search-submit").on("click", function() {
var search = $("#search-input").val(), result = $(".search-results");
result.empty();
if (search !== "") {
$(".box:containsInsensitiveWithCount(" + search.replace(/ /g, ",") + ")").clone(true).appendTo(result);
//the sorting
result.find(".box").sort(function(a, b) {
return $(b).data("matches") - $(a).data("matches");
}).appendTo(result);
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
<input id="search-input" type="text" />
<input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>
To make the search case insensitive you can use a regular expression to find the search term within the text of each .box.
In addition this regular expression can be used to count the number of matches within the .box and then sort() by that value once the loop has completed.
Note in the example below that I added 'Crabapple' value to on of the boxes to that it has two instances of 'apple' to search for. This will always force this result to the top.
Finally, note that I added a call to empty() the result each time a new search is performed. The previous search results were not being removed in your original example.
let $results = $('.search-results');
$("#search-submit").on("click", function() {
let searchArray = $("#search-input").val().trim().split(' ');
$results.empty();
searchArray.forEach(function(word) {
$(".box").each(function() {
let re = new RegExp(word, 'gi');
let matches = ($(this).text().match(re) || []).length;
if (matches != 0) {
$(this).clone(true).appendTo($results).data('matches', matches);
}
});
});
$results.find('.box').sort((a, b) => $(a).data('matches') < $(b).data('matches') ? 1 : -1).appendTo($results);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
<input id="search-input" type="text" value="apple" />
<input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries Crabapple</div>
<div class="box">Lemon Mango Orange</div>
Update
Given the edit to the question you could amend the above logic to build a single regular expression which evaluates all words entered at once:
let $results = $('.search-results');
$("#search-submit").on("click", function() {
$results.empty();
let exp = $("#search-input").val().trim().replace(/\s+/g, '|');
let re = new RegExp(exp, 'gi');
$(".box").each(function() {
let matches = ($(this).text().match(re) || []).length;
if (matches != 0) {
$(this).clone(true).appendTo($results).data('matches', matches);
}
});
$results.find('.box').sort((a, b) => $(a).data('matches') < $(b).data('matches') ? 1 : -1).appendTo($results);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="search">
<input id="search-input" type="text" value="Lemon Pineapple Orange" />
<input id="search-submit" type="submit" value="Submit" />
</div><br/>
<div class="search-results"></div><br/>
<div class="box">Apples Banana Blueberries</div>
<div class="box">Cherries Pineapple Strawberries</div>
<div class="box">Lemon Mango Orange</div>
i don't know much regex so if some one can help me with this it would be great i have a input box and a button.
if the user enters A12345678 the first character should always be A and the rest should always be numbers and altogether it should have less then 10 characters
<input type="textbox" id="id" />
<input type="submit" id="submit" />
<script type="text/javascript">
/*Check if ID is correct */
$('#id').keyup(function(){
var id= $(this).val();
if(id == /*'A12345678' */{
//enable button
}else{
// disable button
});
</script>
i would appreciate if some one could help me out a bit with this
Here ya go ^(A\d{1,9})$;
^ will start the verification at the beginning of the string
() encapsulates your result. not necessarily needed, but I like to have them
A will match the uppercase character
\d{1, 9} will match 1 to 9 numbers following the letter A
$means the end of the string
Use:
if(id.match(/^(A\d{1,9})$/)) {
// do stuff
}
Hope this helps.
Watch it work: https://jsfiddle.net/ppmr12v6/
I am writing a program that needs to parse each word of a sentence which user is inputing in a text field and performs work of outputing each word of the sentence to a seperate line. I am very close, i was able to get it to do so with the replace function on every space to replace with a but it is only doing it to the first space. How could I get it to repeat it with every space not know how many words the user will input in his sentence? So far this is what I have.
<header>
<h1>Parse Test</h1>
</header>
<br>
<p>Please enter facts:</p>
<input id="inp" type="text">
<br>
<br>
<button type="button" onclick="pass()">Process</button>
<br>
<p id="iop"></p>
<br>
<script>
function pass() {
var lx = document.getElementById("inp").value;
var tx = lx.replace(" ","<br>");
document.getElementById("iop").innerHTML = tx;
}
</script>
You can pass a regular expression, and tell it to apply globally with the g flag:
var tx = lx.replace(/ /g, '<br>');
Simplified working example:
console.log('A few different words'.replace(/ /g, '<br>'));
I'd like to have an input area that a user can specify a list of words or strings(such as "www.", ".com", "Random Word" ) that will be filtered out of a list of words also submitted by the user. I've seen the use of .map and .replace but i'm not sure how to use the input submitted by someone.
Thanks for the help.
The following will search the data array for each of the words in the text field (searchTerm). It's currently separating the term on space, but you could easily change that to a comma or any other number of ways of splitting it up, including using a regex to allow for multiple word search terms (i.e. "Random Word"). Anything in the search term will be filtered from the array into the result variable. The search is case sensitive (also easy to change).
var data = [ 'Hello', 'World' ];
function buttonClicked() {
var element;
element = document.getElementById('searchTerm');
var searchTerms = element.value.split(' ');
var result = data.filter(
e => -1 == searchTerms.indexOf(e)
);
console.log(result);
}
function init() {
var element;
element = document.getElementById('button');
element.addEventListener('click',buttonClicked,false);
}
window.addEventListener('DOMContentLoaded', init, false);
<body>
<form>
<input id='searchTerm' type='text'>
<input id='button' type='button'>
</form>
</body>