0

I trying to implement a search for my webapp but somehow regex is not working fine. as flags i have i,m and g

the Markup:

<form role="form">
    <input type="text" id="search" placeholder="Search...." />
 </form>

The Script:

 $('#search').keyup(function(){
     var searchFieldValue = $('#search').val(),
         re = new RegExp(searchFieldValue, "img"),
         str = "The sky is awake so I am awake so we have to play";
     if ( str.search(re) == -1 ){
         console.log("Does not contain " + searchFieldValue );
     }else{
         console.log("Contains " + searchFieldValue);
     }
 });

DEMO

Problem:

typing The sky is awake will return true

but typing we have to play the will return false we have the sky we will return false

How can i solve this since we have the sky is part of str (not as index but all single words are in str)

What i want :

I want that if each and all words are in the str then return true no matter the index of each words

thank you!

Gildas.Tambo
  • 22,173
  • 7
  • 50
  • 78
  • 1
    Unless I'm looking at this very wrong, `"we have the sky"` is *not* a substring of `str` in the code sample you've shown. – David Thomas Jun 14 '14 at 14:29
  • not as index but all single words are in `str` – Gildas.Tambo Jun 14 '14 at 14:30
  • So? The regular expression is looking for the substring as you've passed it to `new RegExp()`, what's the output you'd expect, or want, in this case? – David Thomas Jun 14 '14 at 14:31
  • i want that if each and all words are in the `str` then return true no matter the index of each words – Gildas.Tambo Jun 14 '14 at 14:32
  • if I type "the we have to" into a test fiddle then that doesn't return true for me... Tested on this fiddle: http://jsfiddle.net/X2b8F/ – Chris Jun 14 '14 at 14:35
  • The problem is that you are not understanding how regular expressions work. They don't work as you are expecting them to. to match any of those words your regex would need to be something like `(we|have|the|sky)` to match any of those words. – Chris Jun 14 '14 at 14:37
  • @Chris thank you but it is hard to do that since it is a live search it would be something like (w|e|h|a|v|e|t|h|e|s|k|y) and i don't want that – Gildas.Tambo Jun 14 '14 at 14:39

2 Answers2

1

Split the string in words and check each word:

jsfiddle update

$('#search').keyup(function(){
    var searchFieldValue = $('#search').val();
    var searchedWords = searchFieldValue.split(' ');
    var contains = []; var notContains = [];
    for(var i in searchedWords){
        var re = new RegExp(searchedWords[i], "gim");
        var str = "The sky is awake so I am awake so we have to play";
        str.search(re) == -1 ? notContains.push(searchedWords[i]): contains.push(searchedWords[i]);
    }
    console.clear();
    var resStr = str;
    if( !notContains.join(' ') )
        for(var i in contains) resStr = resStr.replace(contains[i],'');
    console.log('Words not typed yet: '+resStr);
    console.log('is everything typed: '+!resStr.trim().length);
    console.log('is everything typed an nothing more: '+(!resStr.trim().length && contains.length >= str.split(' ').length));


    console.log("Each and all words are "+(!notContains.join(' ')?'':'not all ')+"in the str.");
    console.log("Does contain: ",contains.join(' ') );
    console.log("Does not Contain: "+notContains.join(' '));
});
joopmicroop
  • 891
  • 5
  • 15
  • @kougiland tkx I just updated the fiddle and answer with the a check for your specific needs. – joopmicroop Jun 14 '14 at 15:48
  • somehow when i inter `the the the sky is ` it returns true and `the sky is zzz` will return true and move only `zzz` to false – Gildas.Tambo Jun 14 '14 at 15:52
  • actualy `the sky is zzz` returns false the test returns `... words are NOT all ...` – joopmicroop Jun 14 '14 at 16:09
  • `the the the sky is` each of those words exist in the string.. If you also want the amount of correct words to match then you'd have to do some word cointing of each word. But the answer is still a valid one... – joopmicroop Jun 14 '14 at 16:13
  • I updated the fiddle again to add word counting for you. – joopmicroop Jun 14 '14 at 16:57
1

The easiest way I can see to do this, using a modern browser, is:

$('#search').keyup(function (e) {
    // we're splitting on the white-space characters, therefore they don't
    // seem a useful character to run this function on:
    if (e.which !== 32) {
        var searchFieldValue = $('#search').val(),
            str = "The sky is awake so I am awake so we have to play",
            // splitting the searchFieldValue on white-space (to get
            // individual words):
            words = searchFieldValue.split(/\W+/),
            // using Array.prototype.every() to check that each word entered
            // is present in the string; `every()` will return a Boolean,
            // true: every element in the array returned true for the condition,
            // false: one, or more, element(s) returned false for the condition:
            allPresent = words.every(function (a) {
            // creating a new Regular Expression for each word
            // in order to apply your own approach:
            return str.search(new RegExp(a, 'img')) > -1;
        });

        // just for diagnostic purposes:
        console.log(allPresent);

        // you could, of course, omit the variable and simply return
        // the words.every(function(a){...});
        return allPresent;
    }
});

JS Fiddle demo.

A slightly cheaper approach (avoiding the creation of mutliple regular expression objects):

$('#search').keyup(function (e) {
    if (e.which !== 32) {
        var searchFieldValue = $('#search').val(),
            str = "The sky is awake so I am awake so we have to play",
            words = searchFieldValue.split(/\W+/),
            allPresent = words.every(function (a) {
            // finding the lowercased word inside of the lowercased string:
            return str.toLowerCase().indexOf(a.toLowerCase()) > -1;
        });
        console.log(allPresent);
        return allPresent;
    }
});

JS Fiddle demo.

Edited in response to comment from OP:

[Let's] say [that] I have a [string of] 'awakeness' is there a regex to return false when the user [enters] 'awake' only?

Yes, but this does involve using the more expensive multiple-RegExp solution:

$('#search').keyup(function (e) {
    if (e.which !== 32) {
        var searchFieldValue = $('#search').val(),
            str = "awakeness",
            words = searchFieldValue.split(/\W+/),
            allPresent = words.every(function (a) {
            // the change is the following line, which matches word-boundaries:
            return str.search(new RegExp("\\b" + a + "\\b", 'img')) > -1;
        });
        console.log(allPresent);
        return allPresent;
    }
});

JS Fiddle demo.

References:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • the first returns true even if not all words are typed. – joopmicroop Jun 14 '14 at 17:00
  • @joop: what? The point -as I understand the question- is to check that all words that are typed are present in the string. Which seems to work when I try it. – David Thomas Jun 14 '14 at 17:29
  • @DavidThomas Thank you. Can you please tell me why you need to write `if (!Array.prototype.every)` ? is it to check if the browser support it or what is it for? every is ECMAScript5 – Gildas.Tambo Jun 14 '14 at 18:17
  • 1
    It's to account for those browsers that don't, natively, implement the `Array.prototype.every()` method (there's a small compatibility chart in the page linked-to in the references), but basically IE 8 and lower don't implement it. – David Thomas Jun 14 '14 at 18:23