-
Re: Adding a dictionary instead of a list
I am getting this error:
Code:
has_key is not a member of Systems.Collections.Generic.Dictionary(Of String, is not a member of Systems.Collections.Generic.IEnumerable
From here:
Code:
if replacements.has_key(parts(0))
replacements(parts(0)).Add(parts(1))
Also,
Code:
Add is not a member of Systems.Collections.Generic.IEnumerable
-
Re: Adding a dictionary instead of a list
Quote:
Add is not a member of Systems.Collections.Generic.IEnumerable
Damn, that's true. You need a concrete type rather than an interface. I would suggest a List.
Change this:-
Code:
Dim replacementWords as List(of String)
to this
Code:
Dim replacementWords as List(of String)
and this:-
Code:
Dim newWordList As IEnumerable(Of String)
to this
Code:
Dim newWordList As List(Of String)
Quote:
has_key is not a member of Systems.Collections.Generic.Dictionary
Had a quick google, it ContainsKey not has_key
-
Re: Adding a dictionary instead of a list
And here:
Code:
replacements As New Dictionary(Of String, IEnumerable(Of TextReplacement))
-
Re: Adding a dictionary instead of a list
Yes, that one too. There's an argument for declaring objects as interfaces rather than concrete types but that's probably just a distraction for you at this stage. Just change iEnumerable to List everywhere it occurs.
-
Re: Adding a dictionary instead of a list
I was forced to change to the following as a result of the changes made above:
Code:
If replacements.ContainsKey(parts(0)) Then
replacements(parts(0)).Add(parts(1))
Else
Dim newWordList As List(Of String)
newWordList.Add(parts(1))
replacements.Add(parts(0), newWordList)
But these parts are saying:
parts(1)
Code:
Value of type 'String' cannot be converted to 'WindowsApplication1.TextReplacement
newWordList
Code:
Value of type 'System.Collections.Generic.List(Of String)' cannot be converted to 'System.Collections.Generic.List(Of WindowsApplication1.TextReplacement)
-
Re: Adding a dictionary instead of a list
Change this:-
Private replacements As New Dictionary(Of String, IEnumerable(Of TextReplacement))
to this:-
Private replacements As New Dictionary(Of String, IEnumerable(Of String))
-
Re: Adding a dictionary instead of a list
It worked but only showed one suggestion instead of many suggestions.
-
Re: Adding a dictionary instead of a list
Could it be, because Add is not a member of Enumerable, and Equals is the cause of this limitation?
Code:
If replacements.ContainsKey(parts(0)) Then
replacements(parts(0)).Equals(parts(1))
-
Re: Adding a dictionary instead of a list
E.g. If we are replacing the word bad. Here are the suggestions we should use:
Code:
bad|counterproductive (means negative)
bad|inappropriate
bad|unsuitable
-
Re: Adding a dictionary instead of a list
You certainly shouldn't be using Equals. Where did that come from?
I made a mistake in my previous post, I should have said:-
Private replacements As New Dictionary(Of String, List(Of String))
You should not reference iEnumerable anywhere in your code. Change it to List everywhere it occurs. Once you've done that the Add will be allowed.
-
Re: Adding a dictionary instead of a list
Very good it is working. I don't know how to thank you. It is working fine. Do you anything to do with ignore functions?
-
Re: Adding a dictionary instead of a list
I will consider this as a paid service.
-
Re: Adding a dictionary instead of a list
Wait, that logic is wrong and I'm not even sure where it came from. It's not the logic I posted back in post 32. Go back to post 32, read the code I posted, understand it, and only then should you use it. And don't forget, I have no ide in front of me. I will make mistakes so if you try and use my code without understanding it you will not spot those mistakes and it will fail.
Let's recap:-
Your replacements dictionary is a dictionary of lists. It is keyed by the word you want to replace (checkWord) and each element is a list of words you would use to replace that checkWord. Correct? So your dictionary should be declared like this:-
Code:
Dim replacements as new Dictionary(of string, list(of string))
See how that's a dictionary keyed by a string (this will be your checkWord) containing lists of strings (the valid replacements for each checkWord)
Now you are going to iterate through your file getting pairs of words - the first (part(0)) is the checkWord and the second (part(1)) is a valid replacement. JM showed you how to do this:-
Code:
Using reader As New StreamReader("file path here")
Do Until reader.EndOfStream
Dim parts = reader.ReadLine().Split("|"c)
'Here we will update the dictionary using part(0) and part(1) - see blow
Loop
End Using
Now, when populating replacements, each pair of words in your file is going to be a checkWord and a possible replacement. You might have already created an element in the dictionary for that checkWord or you might not so you need to check:-
Code:
If replacements.ContainsKey(part(0))
Do you see how that's going to return true if the checkWord (Part(0)) has already been placed in the dictionary?
If the checkWord is already in your dictionary it means you have already found at least one replacement word for this checkWord in your file. In that case you do not add the checkword again. If you try it will fail and you will get the duplicate key already exists error. Instead you should add the new replacement word to the list of words you already hold for that checkWord:-
Code:
replacements(part(0)).add(part(1))
Do you see how replacements(part(0)) is going to return you the appropriate list of replacements for the checkWord you're dealing with? And do you see how .Add(part(1)) will add the newly found replacement word for that list?
On the other hand, if the if statement above returns false it means the checkWord (part(0)) isn't already in your dictionary. It means this is the first replacement we've found for that checkWord. In that case we need to create a new list of replacement words for that checkWord containing the newly found replacement word. Then we will put that new list into the dictionary using the newly found checkWord (Part(0)) as a key:-
Code:
Dim newWordList as new List(Of String)
newWordList.Add(part(1))
replacements.Add(part(0))
Do you understand the logic behind the process we're carrying out? Not just the syntax but the steps we're taking and why we're taking them. Unless you understand the logic you will never get through this so concentrate on that understanding first.
edit>
Quote:
Very good it is working.
Our posts crossed over so I didn't see this. That's great to hear but I'd still urge you to read this post carefully and make sure you've understood the logic correctly. If you haven't it's possible that it might appear to work but still be doing something you don't expect.
-
Re: Adding a dictionary instead of a list
Yes, I understand this part:
Code:
if replacements.contains(parts(0))
replacements(parts(0)).Add(parts(1))
else
Dim newWordList as iEnumerable(of String)
newWordList.Add(parts(1))
replacements.Add(parts(0), newWordList)
end if
-
Re: Adding a dictionary instead of a list
Cool, then I think you're probably there:)
-
Re: Adding a dictionary instead of a list
The only problem I see in the code is something like this:
If you replaced the word gave in a sentence like this:
Code:
You gave a bad advice, irregardless of your intention. You provided a bad advice, irregardless of your intention
With these suggestions:
Code:
gave|produced
gave|provided
gave|supplied
gave|yielded
It will have a problem because of an error coming from here:
Code:
Dim foundIndex = RichTextBox1.Find(checkWord, 0, RichTextBox1.TextLength, RichTextBoxFinds.WholeWord)
After you suggest the word supplied to replace gave, it is Automatically replacing supplied with yielded. Try that wordlist you will see.
-
Re: Adding a dictionary instead of a list
Do you anything to do with ignore functions? I will consider this as a paid service.
-
Re: Adding a dictionary instead of a list
Try the wordlist and you will notice the error it is bringing. It is replacing supplied with yielded without Authorization.
Code:
gave|produced
gave|provided
gave|supplied
gave|yielded
-
Re: Adding a dictionary instead of a list
I'm sorry but I didn't understand that. Are you saying it's picking the wrong replacement word from your list? If so we'd need to see the code you use to do that actual replacement. It's probably in the context menu's click event.
-
Re: Adding a dictionary instead of a list
Yes, I have found a code that can resolve the problem:
Code:
Private Sub ReplaceMenu_ItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles ReplaceMenu.ItemClicked
Dim checkWord = replacements.Keys.ElementAt(nextCheckIndex)
ReplaceMenu.Items.Clear()
For Each replacement In replacements(checkWord)
replacement = e.ClickedItem.ToString()
RichTextBox1.SelectedText = replacement
Next
End Sub
-
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.