Re: Adding a dictionary instead of a list
Look closely at what you're doing here:-
Code:
For Each replacement In replacements(checkWord)
replacement = e.ClickedItem.ToString()
RichTextBox1.SelectedText = replacement
Next
You're taking each possible replacement and putting them into the rich text box in turn. The one that ends up in there is simply the last one in the list. That's not what you want.
I'm going to say the same thing to you as I did previously: think about the logic of what you're trying to achieve before you try and write code.
Re: Adding a dictionary instead of a list
Yes, I see it now. I don't know how I could resolve such a problem in 10 days.
Re: Adding a dictionary instead of a list
:)You get better with practice. But no matter how good you get, there will always be a problem that stumps you.
Re: Adding a dictionary instead of a list
Thanks, from here I think I can take it on! Thanks.
Re: Adding a dictionary instead of a list
Hi, the problem was solved by creating a variable and making it equal to the replacement item.
I can get the exact result I want, but when it reaches a point, it gives me an error. Here is the problem:
Code:
An unhandled exception of type 'System.StackOverflowException' occurred in System.Windows.Forms.dll
The error is pointed at this section here:
Code:
foundIndex = RichTextBox1.Find(checkWord, 0, RichTextBox1.TextLength, RichTextBoxFinds.WholeWord)
From this code:
Code:
Private Sub CheckForReplacementText()
If nextCheckIndex = replacements.Count Then
MessageBox.Show("Check complete.")
End
Else
checkWord = replacements.Keys.ElementAt(nextCheckIndex)
foundIndex = RichTextBox1.Find(checkWord, 0, RichTextBox1.TextLength, RichTextBoxFinds.WholeWord)
End If
If foundIndex > -1 Then
ReplaceMenu.Items.Clear()
For Each replacement In replacements(checkWord)
With ReplaceMenu.Items.Add(replacement, Nothing, Sub(sndr As Object, ea As EventArgs)
RichTextBox1.SelectedText = kamau
CheckForReplacementText()
End Sub)
End With
Next
ReplaceMenu.Show(RichTextBox1, RichTextBox1.GetPositionFromCharIndex(RichTextBox1.SelectionStart + RichTextBox1.SelectionLength))
Else
nextCheckIndex += 1
CheckForReplacementText()
End If
End Sub
Re: Adding a dictionary instead of a list
A StackOverflow means that you've put more and more information onto the memory stack until it overflows. It's usually caused when you accidentally create an infinite loop, which I can see you have done here. Your function is calling itself. It is called CheckForReplacementText and it contains a call to CheckForReplacementText. So once you call it once, it will keep recalling itself infinitely.
In fact, as I look at that function I cannot follow any logical train of thought through it at all. What is it trying to achieve? How does it achieve that goal? I can't tell.
Sorry to harp on the same point but this is really important and you don't seem to be getting it: Think about the logic of what you're trying to achieve before you write a single line of code. Turn off your computer, go and get a pencil and piece of paper and write out your algorithm in pseudo code. Do not try and use your code window as a place to design your algorithm - it will confuse your thinking and make things much harder. Instead, describe a set of steps in plain English on a piece of paper. Only once you're happy that your set of steps is bomb proof and will achieve exactly what you want it to should you turn your computer back on. even then you will probably get half way through coding and realise there's something you forgot. That's fine, just turn the computer back off again and revisit your piece of paper.
Jumping straight into code is always tempting but, when you're stretching yourself to work out a decent algorithm, it will make your life much, much harder.
Re: Adding a dictionary instead of a list
Yes, very true! I know the CheckForReplacementText has been called way too many times. I tried to reduce it by removing the function from the contextMenu below, but there was no way for me to be able to move next Automatically to the next replacement without pressing F1 key.
Also, because when I remove the function from the Context, it still produces the same error or the program suddenly fails to work by prompting that error. Have a look at this code:
Code:
With ReplaceMenu.Items.Add(replacement, Nothing, Sub(sndr As Object, ea As EventArgs)
RichTextBox1.SelectedText = kamau
End Sub)
Also, because my level of programming is rather limited, I have been working with problems, and progressing slowing. Like I have now been accustomed to solving type strings that cannot be converted into 1 dimensional array of String. I know it will take time, but also there is no search engine that can get you exactly what you want. I have enjoyed some success with GoodSearch, and Dogpile, but still most problems cannot be solved on a dime!
Re: Adding a dictionary instead of a list
You're still talking about code. Stop looking at code. Right now it is in your way. You're still not thinking about the logical steps. Just answer the following simple question:-
What is the purpose of the Function CheckForReplacementText?
Re: Adding a dictionary instead of a list
The purpose of this function is to achieve the following:
1. To first check for the word to replace
2. To clear the list of the previously replacements if the search had already occurred, and to put a new list when the next word is found on the RichTextBox with the checkWord at the
Code:
checkWord = replacements.Keys.ElementAt(nextCheckIndex)
3. To create an index of the found word with the assistance of the foundindex Integer from the first position which is to check for a word from the first position of the TextLength which is 0, to the Length of the Text with the help of the
Code:
RichTextBox.TextLength
from that position.
4. I believe the checkWord is the String that the
Code:
RichTextBoxFinds.WholeWord
function will try to Locate. But in order for it to do so, there has to be a location to check where the word can be found! This, I believe is from the Zero(0), and collection of the Length of that Text from 0 to the end of that position with the aid of the
Code:
RichTextBox.TextLength
.
5. That is where
Code:
If foundIndex > -1 Then
comes in!
6. The proceeding steps will now be to locate the matches of that word from the dictionary, and to find Alternative text from that dictionary. In this case, would be from the second column of that dictionary.
7. Now, the complex part would be to load the alternative items found from the dictionary, and to load them according to the order they were found into the ContextMenuStrip.
8. The contextMenu has two parts: one for loading the replacement which is a subItem from a list of items that were found from the checkWord.
9. The second part is the replacement part from that position that was measured in the RichTextBox, with the new text from the ContextMenu.
10. To show the menu on the RichTextBox with the aid of this code:
Code:
ReplaceMenu.Show(RichTextBox1, RichTextBox1.GetPositionFromCharIndex(RichTextBox1.SelectionStart + RichTextBox1.SelectionLength))
11. The last part is the confusing part because I don't know how to rewrite it, because as it states:
Code:
Else
nextCheckIndex += 1
CheckForReplacementText()
End If
Its work is to do the next checking by adding +1 to the next check, which would prompt it to begin from scratch, and to check from the last position, which would not be zero, but the last position where it replaced the text because one has been incremented from here:
Code:
nextCheckIndex += 1
.
This will tell the function that
Code:
If nextCheckIndex = replacements.Count Then
this section has now been incremented by one, and to move the index from the first found index from 0 to 1 from the following code:
Code:
foundIndex = RichTextBox1.Find(checkWord, 0, RichTextBox1.TextLength, RichTextBoxFinds.WholeWord)
This is confusing, but it is the part where the CheckForReplacementText() function will come. I have once tried to remove it, but the checking occurred only the first time, but never occurred again.
Re: Adding a dictionary instead of a list
I didn't ask what it does do, I asked what it's meant to do. And you're still clearly looking at the code - stop! The reason I asked what it was meant to do is that we've already established that what it does do is flawed, otherwise we wouldn't be having this conversation. Forget about the code that's there - it's wrong and we're going to throw it away. We're going to write new code and it will be code that you understand.
I'm going to summarise what I think it's meant to do for you:-
1. Select the whole word that might require replacement
2. Check the dictionary to see if that word is present
3. If that word is in the dictionary then present the user with a context menu containing all the possible replacement words, otherwise advise them that there are no replacements.
4. Allow the user to select a replacement word
5. Delete the text that was selected in step 1
6. Insert the replacement word that the user selected
Is that a fair summary of the purpose of the function? If it is then a problem should immediately jump out at you when you read step 4. You need to respond to a user action. How do we respond to actions? We catch events and call functions from them.
So you're going to need two functions. The first function will carry out steps 1 to 3 and, by the look of things, you want this to be called in response to the user pressing F8 (I'm not sure that's a great choice but I can see where you're coming from with it - it's not crazy). The second function will carry out steps 5 and 6 will be called in response to the user selecting a replacement word.
Are you happy with everything I've explained so far? Have I understood your requirement correctly?
Re: Adding a dictionary instead of a list
Yes, that is true. I was proofreading and grammar checking to make it sensible
Re: Adding a dictionary instead of a list
OK, great. So we've got an easy to understand description of the algorithm. We've also identified that you're going to need two separate functions and that trying to cram the whole lot into one was a non-starter. So lets attack the first function first - let's get it to the point where it's at least presenting the user with a list of replacements.
Let's take step 1. We need to select the word to be replaced. What does that look like? From the code in post 1 I think you trying to pick every word in the text box in turn, is that right? If so step 1 is going to break down to a bunch of sub steps with some looping in it:-
1.1 Start at the beginning of the text box
1.2 Select the next word in the text box
1.3 Is a word found?
If Yes
...1.4 Carry out steps 2 to 3 (steps 5 and 6 will also occur but they will be in response to a separate user action so will have their own function)
...1.5 Move to the end of the word we just checked
...1.6 Go to 1.2
If No
...1.4 End
Can you see how that describes the individual steps you need to take to take to work your way through the text box. I'm going to stop there because I'm not sure my assumption that you're checking each word in the text box in turn is correct and I don't want to head too far up any blind alleys. Can you confirm that assumption was correct and we'll go further?
Re: Adding a dictionary instead of a list
That Pseudo code is more easy and flexible. I think that will help the program to function easily, and faster.
Re: Adding a dictionary instead of a list
Cool, but can you confirm I was right in my assumption. Are you intending to check each and every word word in the rich text box in turn when the user presses F8?
Re: Adding a dictionary instead of a list
Yes, F8 was the original, but I will prefer F1 for quick access and locating from the keyboard. Any will do, but one can edit to suit his or her needs.
Re: Adding a dictionary instead of a list
While your working on it, I will also try to come up with a code based on that Pseudo code.
Re: Adding a dictionary instead of a list
Quote:
While your working on it, I will also try to come up with a code based on that Pseudo code
Really?! After all I've said you still think the next step is to start writing code?! You should be the one creating this pseudo code, not me. You should not be touching your code window yet because this pseudo code is not finished. You still haven't finalised the logical steps you need to carry out and that's what you should be doing.
Step 2 is easy. It doesn't break into sub steps. It a single step:-
2. Check if the dictionary contains the selected word as a key.
But Step 3 is more complex. You need to break "present the user with a context menu containing all the possible replacement words" into a series of discrete steps in much the same way as I did with Step 1. If you cannot write them as steps I guarantee you cannot code them as steps. So write them. I'm not going to do it for you.
Re: Adding a dictionary instead of a list
Yes, sorry for that, I somehow got confused and did not understand what you were asking. I now know everything you asked, and will write that Pseudo code based on that assumption. I completely understand that cramping everything in one function is wrong. I also learnt that one needs to break the code into small sections so that it will be understandable, and easy for the computer to use. Let me write the Pseudo code now.
Re: Adding a dictionary instead of a list
OK, the first step is to create two functions:
Code:
1. CheckWordFromTheDictionary()
2. MoveNextFunction ()
Step. 1
CheckWordFromTheDictionary() Function
Code:
If RichTextBox is Not Null,
(A.) Check if the first word is in the dictionary
If the first word is found,
(B.) take the suggestions from the second column, and store them in a Variable.
Else if the word from the RichtextBox is not found,
MoveNextFunction Function
Code:
1.1 The MoveNextFunction will move to the next word in the next index of the RichTextBox1.
1.2. Use step (A.) and (B.), but at the next index of the RichTextBox to check if the word is in the dictionary.
1.3. If the MoveNextFunction does not find the word, it will move to the next word in the RichTextBox with the help of step 1.2.
Step. 2
Code:
If word from the first step was found.
2.1. Highlight the word to be replaced.
Clear the ContextMenu because of repetitive tasks, and
2.2. Load the items into the ContextMenuStrip.
Step. 3
Code:
OnButtonClick_Event
3.1. Raise the event that will trigger the step 1 and 2 to be executed and the Menu to be displayed to the user on the RichTextBox.
3.2. If no matches of any given word were found by the MoveNextFunction in Step 1,
A messageBox.Show function should now appear with a message that "No Matches were found in the whole document."
When the user clicks the OK button of the MessageBox,
The CheckWordFromTheDictionary() Function should be stopped without closing the whole form.
Step .4
Code:
If matches were found, display the ContextMenu, and allow the user to select what he or she wants.
ElseIf the suggestions are not good. The MoveNextFunction will be called.
Else if the suggestions are good. Replace the selected word.
Step. 5
Code:
It will now wait for the User to click the button again for the CheckWordFromTheDictionary() Function to be called.
Else. The code waits.
Re: Adding a dictionary instead of a list
That looks like a pretty decent stab at it. I'd offer up a couple of bits of constructive criticism:-
1. Move away from expressions like "first word". You really want to look at the "current word". (On the first check the current is the first word, of course, but after that it won't be)
2. You still haven't really got the order of the steps right. E.g. Your step 3.1 should be the first thing that happens. After that should come Step 1. Steps 2 and 4 would happen for each word the MoveNext function finds. Step 3.2 describes the end of the process and step 5 is really just describing your idle state.
3. You could probably tighten this up a little by "embedding" steps within other steps. E.g. the MoveNest steps actually happen between 3.1 and 3.2. And really there's a loop between 3.1 and 3.2 that repeatedly calls MoveNext then CheckWordFromDictionary.
You're getting pretty close but I'd suggest one last stab at this before you move to code. Believe it or not we're actually much closer to a solution than you might think. You're previous posts contain all the syntax you're going to need to implement this so, once we've got the steps right, converting it to code should be reasonably easy.
Re: Adding a dictionary instead of a list
Code:
1. CheckWordFromTheDictionaryFunction()
2. MoveNextFunction ()
Step .1
OnButtonClick_Event
Code:
3.1. Raise the event that will trigger the CheckWordFromTheDictionaryFunction.
Step. 1.A.
Duties: - CheckWordFromTheDictionaryFunction
Code:
1. To strickly check if the currentword is in the dictionary or not. But it should not move next!
Instructions:
Code:
(1.) To check if the RichTextBox is Not Null,
if it is Null, quit. MessageBox.Show("You have no words to check!")
(2.) ElseIf Not Null,
(A.) Check if the Currentword is in the dictionary
If the Currentword is found,
(B.) take the words from the second column, and store them into a CurrentSuggestions Variable.
ElseIf the Currentword from the RichtextBox is not found, call the MoveNextFunction to move to the NextwordIndex.
Step .1 .B
Duties:- MoveNextFunction
Code:
1. To strickly move to the NextwordIndex without doing anything else!
Instructions
Code:
1.1 The MoveNextFunction will move to the NextwordIndex of the RichTextBox, and then call the CheckWordFromTheDictionaryFunction.
1.3. If the CheckWordFromTheDictionaryFunction does not find the Currentword that has been moved to, it will call the MoveNextFunction to move to the NextwordIndex.
Step. 2
Code:
Code:
If the Currentword was found.
2.1. Highlight the Currentword to be replaced.
Clear the ContextMenuStrip.Clear() because of repetitive tasks, and
2.2. Load the items from the CurrentSuggestions variable into the ContextMenuStrip.
Step. 3
Code:
3.2. If no Currentword was found from the dictionary in the whole document by the CheckWordFromTheDictionaryFunction after the MoveNextFunction was called.
A messageBox.Show() function will be shown with("No Matches were found from the dictionary in the whole document!").
When the user clicks the OK button of the MessageBox.Show()
The CheckWordFromTheDictionaryFunction should be stopped without closing the whole program. Otherwise, there is already a Me.Close() function on the BtnClose Button.
Hence, here the program is ideal.
Step .4
Code:
If Currentword was found, display the ContextMenuStrip, and allow the user to select what he or she wants.
ElseIf the Currentword was not good. The MoveNextFunction will be called.
ElseIf the CurrentSuggestions are good. Replace the Currentword with CurrentSelectedSuggestion Item from the contextMenuStrip.
Step. 5
Code:
Code:
It will now wait for the User to click the button again for the CheckWordFromTheDictionaryFunction to be called. We have agreed that the CheckWordFromTheDictionaryFunction is to check the Currentword from where it has been moved to!
ElseIf all the replacements have been made, MessageBox.Show("The task is Completed."). End.
Terminologies
Code:
1. The CheckWordFromTheDictionaryFunction is the function to do the checking.
2. The MoveNextFunction is in charge of moving to the NextwordIndex.
Keywords to be used in the program:
Code:
Currentword, CurrentSuggestions Variable, NextwordIndex, CurrentSuggestions, CurrentSelectedSuggestion Item
Items to be created:
Code:
Button for search, Button for Close, ContextMenuStrip1, RichTextBox1, Connection to a Dictionary path.
Functions to be created
Code:
1. CheckWordFromTheDictionaryFunction
2. MoveNextFunction
Re: Adding a dictionary instead of a list
Now that's what I call a well understood algorithm:). I know it probably felt a bit laborious to get to this point but, believe me, it was necessary and I hope it hasn't put you off programming. As you get more experienced you can probably start skipping a lot of this forward planning and jump straight into code but when you're just starting out it's hugely valuable.
Now you want to start writing code. Create your form, buttons, text boxes etc. (or just reuse the ones you already have) and start turning those steps into code. Add an event to the search button, call the move next function (or possibly call a similar CallFirst if you want to keep them separate) and call the CheckForWord function if you haven't reached the end of the text box. Then write the code for MoveNext and CheckForWord based on the steps you've detailed above.
I'd advise you to do this in small, testable steps instead of trying to do the whole thing at once, it just makes things easier. So first of all get MoveNext working and make sure you can select each word in turn. Once you've done that get checkForWord working and make sure you can pop up an appropriate context menu on each word. Finally, handle the user selecting a word and replacing the text in the rich text box with their selection.
Your previous posts contained all the bits of syntax your need (just in the wrong order) so you might well be able to finish off yourself but if you do get stuck (you probably will, we all do) then post back with your code. Now that you understand the algorithm thoroughly and so do we it'll be MUCH easier to get you past any bumps.