Slightly Advance Question about Search Text


#1

Hi guys, I just finished

https://www.codecademy.com/en/courses/javascript-beginner-en-XEDZA/0/7

I’m not stuck. I have passed the lesson. Thus, the topic is slightly out of the ordinary exercise (still falls under this category).

The lesson offer another challenge, that is:

Think about how you might fine-tune this program to make sure it only finds exact matches for your name.

I know, again, I’m just a novice coder. But, I would really like to try push the limit with my current limited knowledge (which is not much to begin with), to see whether I can solve that situation.

So, to quote the situation better, I would like to refer to this discussion here

Back to my code. myName = “Ryan”. Naturally, you would want to search for only your name to be printed out. This case, I have tinkered my code to have different variation of Ryan, (ie: Rya, Ryeg etc). I want to avoid printing anything starts with “R” or not exactly “Ryan”.

So, I arrived into very amateur solution, the full code below:

var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {                //when "R" is found
        if (text[i+1] === myName[1]) {          //when text[i+1] equals to "y"
            if (text[i+2] === myName[2]) {      //when text[i+2] equals to "a"
                if (text[i+3] === myName[3]) {  //when text[i+3] equals to "n"
                    for (j=i; j<myName.length+i;j++) { //only then push the alphabet
                        hits.push(text[j]);
                    }
                }
            }
        }
    }
}

if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}
Code
var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {                //when "R" is found
        if (text[i+1] === myName[1]) {          //when text[i+1] equals to "y"
            if (text[i+2] === myName[2]) {      //when text[i+2] equals to "a"
                if (text[i+3] === myName[3]) {  //when text[i+3] equals to "n"
                    for (j=i; j<myName.length+i;j++) { //only then print the alphabet
                        hits.push(text[j]);
                    }
                }
            }
        }
    }
}

if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}

As you can see in var text, there is only two correct “Ryan”. Thus, it is expected to only see two r,y,a,n in the result.

[ ‘R’, ‘y’, ‘a’, ‘n’, ‘R’, ‘y’, ‘a’, ‘n’ ]

And I got the code running the answer I wanted.

But HERE starts my Real Question. :confounded:

My above code only works if I know the value to var myName.
In other words, if myName is set to

var myName = prompt(“What is your name?”);

the code won’t work because for my case, I knew it would only take 4 conditional checks, four IF statements. (to check R,y,a,n), but for prompt, it could be any string, any length.

And I noticed the pattern (the conditions that I wanted to happen)


if (text[i] === myName[0]) {                //when "R" is found
        if (text[i+1] === myName[1]) {          //when text[i+1] equals to "y"
            if (text[i+2] === myName[2]) {      //when text[i+2] equals to "a"
                if (text[i+3] === myName[3]) {  //when text[i+3] equals to "n"

I thought that is getting repetitive, maybe something else can replace those codes in the middle.

such as:

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
---->   if (        ) {  
---->       //if something checks the rest of myName value
            for (j=i; j<myName.length+i;j++) {
               hits.push(text[j]);
            }
        }                        
    }
}

I was thinking maybe I can try For Loop because it’s repetitive, what I have done is,
create another checking function with a For Loop inside, as below:

var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        return text[i+array] === myName[array];    //return to boolen
    }
};


for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking all true, then only run for loop
            for (j=i; j<myName.length+i;j++) {
               hits.push(text[j]);
            }
        }                        
    }
}


if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}

Code
var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        return text[i+array] === myName[array];    //return to boolen
    }
};

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking all true, then only run for loop
            for (j=i; j<myName.length+i;j++) {
               hits.push(text[j]);
            }
        }                        
    }
}

if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}

But my limited understanding fails me this time.
console printed:

[ ‘R’, ‘y’, ‘a’, ‘n’, ‘R’, ‘y’, ‘a’, ’ ', ‘R’, ‘y’, ‘e’, ‘g’, ‘R’, ‘y’, ‘a’, ‘n’ ]

It kick out any words that don’t follow “Ry” but not the rest of “Ryan”.

Sorry to post such a long topic. I think I need to explain my thought process in detail for someone to be able to offer help/suggestion.

Anyone with a better understanding of JS, maybe can shed light on why my second code will not work? :disappointed_relieved:


Another note: I understand there will be other ways to solve this problem, it could be very fun to see replies on that (I would want to learn it too), as it is hinted in the exercise:

Search the Internet to see if there are any built-in JavaScript string methods that can help!

Pardon me for asking this silly question that might be too much for my current level.
:sweat_smile:


'Search text for your Name' Exercise is not accurate
#2

its a really good question, the problem is here:

var checking = function() {
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        return text[i+array] === myName[array];    //return to boolen
    }
};

a function ends the moment a return keyword is reached. So the loop ends in the first iteration/run

we can do:

var checking = function() {
    all_in = true

then we use a for loop like you have, use if/else to see if all letters match and then return all_in


#3

Ditto to everything stetim has said already.

It's really cool how you've managed to come up with a solution like that at this level keep it up. :wink:

If you'd like to look at another solution here's a similar thread I contributed to that you can check out.


#4

Thanks @stetim94, even if it's just a few words, am glad to hear. Was quite embarrased to ask, such a long post, but brave myself anyway.

This is really really important. Thanks! It makes me realize my fundamental knowledge is still considerably weak. I understand now why the loop would not continue. Smack my head. And because of your hint, I understand return is sort of a conclusion used in the end of a function, because we wouldn't want the for loop to fail running.

Thanks with all the help and hint! :grinning:


#5

Thanks for the words of encouragement! @angusbeef, I need to see how far I can go in this, thus seem bit oblivious sometimes, asking question above my comprehension level. Wanted to see whether coding is my thing, whether my brain can cope with it or not.

Thanks for that link! Really appreciate that, to be frank, I took like one hour to understand every single part of your code even with your given explanation, have to imagine the numbers and map out the process. Literally slowpoke.

I really like that answer! I was thinking to store the push thing in a variable. Then compare it with var myName. But soon, my brain cannot wrap around that idea and have to abandon it.

if(text[k] === myName[depo.length]) {
      depo.push(text[k]);
}

The beauty of your code is, everything is interconnected. When depo.push(), var depo = "Added with string", thus, depo.length increase, consecutively increasing myName[arrayNumber] . That is the thing my current simple brain cannot come to that code arrangement. Classy.

Also, I just learnt about Break through your code. At my current progress, I still have not encounter Break yet.

Would really like to see the hits.push.apply answer if you have some time some other day. Hope not asking too much though. :smile:


#6

I realize my simple brain can’t code the way @angusbeef coded (if I were to write the code before reading @angusbeef’s answer)

His answer is great. Check here

With @stetim94’s suggestion,
I rearrange my code into something like this

var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    var All;
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] === myName[array]) {     //Say text[9+1] mataches myName[1] which is "y"
            All = true;    //var All stays true (currently)                        
        } else {
            All = false;   //If something not matches, All turns false, 
        }
    }
    return All;
};

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking All true, then only run for loop
            for (j=i; j<myName.length+i; j++) {
               hits.push(text[j]);
            }
        }                        
    }
}

if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}
Code
var text = "do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    var All;
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] === myName[array]) {     //Say text[9+1] mataches myName[1] which is "y"
            All = true;    //var All stays true (currently)                        
        } else {
            All = false;   //If something not matches, All turns false, 
        }
    }
    return All;
};


for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking All true, then only run for loop
            for (j=i; j<myName.length+i;j++) {
               hits.push(text[j]);
            }
        }                        
    }
}


if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}

So happy that it printed out :joy:

[ 'R', 'y', 'a', 'n', 'R', 'y', 'a', 'n' ]

BUT

when I change

var text = “do re mi Ryan do re mi Rya do Re mi Ryeg do dRae mi Ryan”;

to

var text = “do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan”;

The console printed out: :sweat:
[ 'R', 'y', 'a', 'n', 'R', 'y', 'e', 'n', 'R', 'y', 'a', 'n' ]

I only realized break is important here, because the final “n” in “Ryen” had changed the var All into true again. Even though “e” in “Ryen” has made All = false, but the final “n” overwrites it and makes All = true again. Therefore, R,y,e,n is printed.

So my final code arrived to this:

var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    var All;
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] === myName[array]) {     //Say text[9+1] mataches myName[1] which is "y"
            All = true;    //var All stays true (currently)                        
        } else {
            All = false;   //If something not matches, All turns false,
            break;         //break the loop for progressing
        }
    }
    return All;
};


for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking All true, then only run for loop
            for (j=i; j<myName.length+i; j++) {
               hits.push(text[j]);
            }
        }                        
    }
}


if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}
Code
var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

var myName = "Ryan";

var hits = [];

//Check whether the rest of myName is equal with what text[i+array] found
var checking = function() {
    var All;
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] === myName[array]) {     //Say text[9+1] mataches myName[1] which is "y"
            All = true;    //var All stays true (currently)                        
        } else {
            All = false;   //If something not matches, All turns false,
            break;         //break the loop for progressing
        }
    }
    return All;
};

for (i=0; i<text.length; i++) {
    if (text[i] === myName[0]) {
        if (checking()) {   //After checking All true, then only run for loop
            for (j=i; j<myName.length+i;j++) {
               hits.push(text[j]);
            }
        }                        
    }
}

if (hits.length === 0) {
    console.log("Your name wasn't found!");
} else {
    console.log(hits);
}

Finally, with “Ryen” in the var text, the console managed to ignore it and printed

[ 'R', 'y', 'a', 'n', 'R', 'y', 'a', 'n' ]

I still unsure whether this code is workable for all situation (Excluding Case sensitive, if “ryan” is in var text, it will not print), that will be for another day.

@stetim94, is this code what you’re hinting at, or you have other in mind?

Anyone who is interested, would you test the code for me with different strings in var text or if someone find a bug, do post a reply here? Greatly appreciate it!

:slight_smile:


Side note: this answer got me another 1.5 hour to come out with after failing attempt plus another 1 hour to understand @angusbeef code :expressionless


#7

Actually, my little help pushed you in the right direction and then you figured it out :slight_smile:

Which is really impressive, and you learn more from it then just being presented with the answer

we can use return (which ends function) to our advantage:

var checking = function() {
    var All;
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] === myName[array]) {     //Say text[9+1] mataches myName[1] which is "y"
            All = true;    //var All stays true (currently)                        
        } else {
            retrun false;
        }
    }
    return true;
};

we simply use return to end the function (and thus break the loop)

using this approach, i realized could make it even more efficient:

var checking = function() {
    for (array=1; array<myName.length; array++) {  //Start array=1 because myName[1]="y"
        if (text[i+array] !== myName[array]) { 
            return false;
        }
     }
     return true;
}

we simply return false when the current letter in i doesn't match with the current letter in myName

this means, that if the loop finishes running, true will be returned

Any questions remaining or all clear now? Really impressive what you did, many people wouldn't have gotten this far all by themselves


#8

I agree that it's very good question. In my solution I used ES6 and jQuery.map() method. You can try it here.

First I converted text to array of words which are separated by whitespace. Using .map() helped me to iterate through the created array and find all hits.

So, in my solution I didn't use any built-in JS strings methods but I think it's can be a good example how to resolve this problem.


#9

Thanks @stetim94 for the explanations!

If I understand this correctly, when return is used, any function would stop running and return the value after return. So, if return is used inside a for loop, whenever it executes return value, the loop will not continue anymore, even though the i<variable.length condition still not fulfilled?

Thus, { All = false; break; } (assign false to var All, then break the code) would carry the same meaning as { return false; } ?

Ah, so there's no such need to declare a variable All. We want to know in case there's something not match between text[i] & letter in myName, we just want to discard the process and use return false to break the loop ?

I think I gained more understanding about return with your code as reference. As you can see, I dare not play around with return for my very last code due to my previous failed attempt using return in a for loop.

Really thanks for your help and kind words. Would still in the dark if I were to do this alone, certainly not all by myself. :slight_smile:

I still have a few conditions that I wish to solve for this matter, will back to this when I have the time and improvise my code.


#10

@denys.matsevych, thanks for sharing your answer here! :smile:

I gotta say, just started JS just early of this month. So pardon me for not able to fully understand your code using jQuery (I've read jQuery is an extension of JS library something like that) as there are some jargon that I still not encounter.

One thing I noticed which is different with @angusbeef and my code is that, your code seems to search for the name as a whole (maybe due to the method of white space). It would be like search for exact word function, which is what the exercise mentioned:

fine-tune this program to make sure it only finds exact matches for your name.

Therefore, if myName = Rae, I would not find it in dRae which is in

var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

which also means, if myName = "Rya", your code will find only one match

var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

As compared to my code, if myName = "Rya"

var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

I will get 3 found results.

Initially I thought to create something like a Microsoft Word basic search function. It means that if I want to search for "Rya" , it will highlight for me 3 found matching result:

var text = "do re mi Ryan do re mi Rya do Re mi Ryen do dRae mi Ryan";

After toying with your code, I find your code result is what the exercise aiming for. Rather than searching matching letters, it also requires match the whole word exactly.

Thanks for sharing your answer in jQuery. Even though I might not understand it now, I can come back and refer it someday. :innocent:

As I mentioned I have few more conditions wished to solve all together. Matching whole word exactly will be one of them.


#11

well, return ends the function immediately where using All would mean you need to update a variable, and the loop breaks, the rest of the function needs to run


#12

I've found some built-in JS functions:
.indexOf()
.search()

You can try:
1. Convert string to array of words.
2. Find all hits.
3. Print result.

Example:

function find(str, name) {
  var hits = 0;
  
  for (var i = 0; i < str.length; i++)
    if (str[i].search(name) != -1) {
      hits++;
    }
  
  return hits;
}

The reason of using step 1 is that built-in String functions such as .indexOf() or .search() returns the index of the first occurrence of the specified value. So, using these functions with var text returns only 1 (the first) hit.
Try to use my example, hope it help you to find the best solution.


#13

Okay I follow the logic now, it would be more efficient to use Return instead of updating All everytime. Thanks! :smile:


#14

Thanks for introducing new built-in JS functions and the suggestion of step 1 @denys.matsevych , will take sometime to process this info and to understand the info in .search() & .indexOf() as well. :grinning:


#15

If you have time left, look into regular expressions. They can also be used, and then it will be interessting to measure how the functions preformances are


#16

Thanks. Found this, I search mainly in this mozilla web as CC recommended it as reading material.

It's a loong read. :joy:


#17

@denys.matsevych, I just go through your code again in

https://repl.it/Iq47/9

Even though there are still few terms that I don’t understand such as let , const , $ etc.
I think we can just put them aside as I have zero knowledge in jQuery (wouldn’t want to trouble you explaining everything here and I probably would not understand all)

My question: I noticed there’s a .split() under function convertStringToWordsArray(str)

I was mulling over your recommendation in Step 1. Therefore, I noticed that .split() thing and I arrive to this

Just want to double confirm this, as I don’t want to misinterpret your code. Is that string.split() function that you’re using? :slightly_smiling_face:


#18

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.