Solved

Anagram Solver?

Posted on 2002-05-01
30
758 Views
Last Modified: 2007-12-19
Hi all.

I am currently trying to put together a small access program that will untangle an anagram.
I already have imported a LARGE dictionary file with over 1 million entries. It is very simplistic with a single entry on each line.

I know there are probably loads of ways to do this but I finally decided on using filters on a form. First to exclude all entries that are not of the relevant length.
 
me.filter = "len(dict) = len(field1)"

I then thought that for each letter of the anagram I would add another filter layer that would exclude all those entries without the relevant letters. I got a certain way but couldn't cope with problem of repeat letters. Sysntax was also a problem due to there being only one filter command.

So my questions are.

Is there a way to apply to filters to the same set of data on a form.

Am I going about this the wrong way?

If not then can someone suggest how I might overcome the problem of duplicate letters?

Any other comments/suggestions are encouraged.

Points will be awarded to anyone with any in depth thoughts.

Thanks

Jell

0
Comment
Question by:James Elliott
  • 13
  • 11
  • 4
  • +2
30 Comments
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983292
Hi jell,

No hard feeling indeed....

Please post some examples of the problem, it sounds like a nice head breaking one...

Nosterdamus
0
 
LVL 12

Expert Comment

by:Paurths
ID: 6983293
hi jell,

how about using the (total) ascii value?

u would need an extra column in your table where the ascii value of the word is stored.

then calculate the value of any given word,
and filter on that value.

perhaps adding up isn't a good idea, but multipliying should produce good values.

just a quick thought...
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6983323
I'll post some examples in a sec.

Paurths, nice thought.

However, wouldn't we end up with more that one answer. The dictionary I have is actually a password hacking dictionary. And trust me it's huge. The are many combinations of the same words. (e.g example, eaxmple, exampel etc.)

Could your Ascii method be adjusted to acommodate this.

Thanks

Jell

Still open to other methods.


0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983329
Build an index of the letters that makes the word.

Example:

Gear and Rage use the same index: aegr

what you have to do is build a sorted index of all your words and then show them according to their index relationship.

Just a thought...

;-)

Nosterdamus
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983346
correction:
Gear and Rage use the same index: aegr

should read:
Gear and Rage use the same index KEY:aegr
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6983351
Another good thought. Thanks.

If poss, I would like to do this as 'programmaticaly' as possible. Ideally I would like one table(dictionary), one form with two fields and a button. This is probably not realistic but I would rather not start making queries and index tables etc.

However, I am prepared to use whatever works. Simplicity is just a preference.

Thanks

Jell

Examples on the way

0
 
LVL 12

Author Comment

by:James Elliott
ID: 6983387
I've used this to go through each letter in turn of the anagram:

Dim charnum As Integer
Dim strvar As String

Text0.SetFocus
strvar = Text0.Text
charnum = Len(strvar)

For i = 1 To charnum
strvar = Left(Text0.Text, i)
strvar = Right(strvar, 1)
MsgBox "" & strvar
Next i

I then tried to cocantenate the filter function to read something like

me.filter = "instr(1,field1," & str & ") <> 0" etc.

This is were I was getting annoyed with there being only one filter. I was trying to use the next i funtion above to cocantenate a string which I could use a big filter criteria using the AND operator.

As you can imagine the syntax was a nightmare.

Thanks

Jell
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983420
Ok jell, try the following little function and see if it suits your need...

Public Function BuildTheIndex(strWord As String) As String
    Dim i As Integer
    Dim j As Integer
    Dim strArr() As String
    Dim strTemp As String
   
    ReDim strArr(Len(strWord))
    For i = 1 To Len(strWord)
        strArr(i) = LCase(Mid(strWord, i, 1))
    Next i
   
    For i = 1 To UBound(strArr)
        For j = i + 1 To UBound(strArr)
            If strArr(i) > strArr(j) Then
                strTemp = strArr(i)
                strArr(i) = strArr(j)
                strArr(j) = strTemp
            End If
        Next j
    Next i
   
    strTemp = ""
    For i = 1 To UBound(strArr)
        strTemp = strTemp & strArr(i)
    Next i
   
    BuildTheIndex = strTemp
   
End Function


Public Sub test()
    Const MyText = "This Is A Sample"
    Dim ReturnResult As String
   
    ReturnResult = BuildTheIndex(MyText)
   
    MsgBox "Original string = " & MyText & vbCrLf & vbCrLf & _
           "IndexKey string = " & ReturnResult
End Sub

You can run the test subroutine to see how it works.

Now, add a new field to your table (MyIndex???) and set it to indexed (allow duplicates). Create an update query to build your index:

Update MyTable Set MyIndex = BuildTheIndex(MyField)

This will create the index.

In your form, on the UfterApdate event of your textbox, place:

Me.Filter = "[MyIndex] = BuildTheIndex(Me.MyTextBox)"


HTH,

Nosterdamus
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983424
Correction:
In your form, on the UfterApdate event of your textbox, place:

Should realy read:
In your form, on the AfterUpdate event of your textbox, place:

;-)

Nosterdamus
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6983428
Hold all comments while I test it.

Thanks

Jell
0
 
LVL 8

Expert Comment

by:dovholuk
ID: 6983444
ok, here's a wierd idea...

what if you (one time job) add another column to your db of words that counts the number of letters using a 26-character length string such as:

{abcdefghijklmnopqrstuvwxyz}

bob  = {02000000000000100000000000}
tom = {00000000000010100001000000}
bill = {01000000100200000000000000}
     
this will take a while i'd assume as you'd process a recordset, but once it's done, it'll be DONE... know what i mean?

then you take your anagram and add up the count of each letter and you find the matching prhase...

such as: libl (=bill) = {01000000100200000000000000}

then you do a select from your word table where the result matches that new colum to find all the values that match, then you select from that result set...

adding ascii values won't work, though it's a good idea (and my original thought! :)) because a word with a length of 3 and an ascii value of 330 could be : "nnn", "mno", "lnp" "ttb" etc...

i don't have a clue of how you'd extend this to multiple words... it's just an idea! :)

dovholuk
0
 
LVL 1

Expert Comment

by:CSimpson
ID: 6983445
Just a suggestion,

Take your dictionary and index it by each word in an alphabetize anagram. I.e. dictionary = acdiinorty

Then alphabetize your anagrams you wish to solve and look up matches in dictionary.
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6983447
I now you said "Hold all comments" but I found another error that should be corrected:

Me.Filter = "[MyIndex] = BuildTheIndex(Me.MyTextBox)"

should be:
Me.Filter = "[MyIndex] = " & BuildTheIndex(Me.MyTextBox) & ";"
0
 
LVL 8

Expert Comment

by:dovholuk
ID: 6983479
sorry about "no more posts", i was still typing...

but now i'm wondering...

is this going to extend to more than one word? if so, take the word: teammate... scramble it into mmeettaa... does this "unscramble" to team mate or to teammate? how does the computer know? does it display all possibilities like the "what does your phone number spell" sites?

just wondering...

dovholuk
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6983577
Nosterdamus

Tried it but couldn't get the filter to work.

I've done the update query (which took 20mins BTW!) but I can't seem to inegrate this into my form.

Say I have two fields: InputF and OutputF

InputF is obviously where I will enter the anagram. OutputF is where I want my answer(s). Does OutputF have the index field or the word field as it's control source?

Which field does your AfterUpdate go.

Can you write me some new script around the above. I would like the code to go on a button that will process the anagram.

Thanks

Dovholuk -

Great idea. Would have any advantages over the method I'm trying to use at the moment?

In the future I want to expand this by getting it to solve an anagram puzzle. I'e. how many words of 5 - 9 letters can be found. etc.

Any thoughts?

At the moment I'm not bothered if the function returns a couple of results (e.g. team mate or teammate.)

Thanks

Jell
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 12

Author Comment

by:James Elliott
ID: 6983581
sorry for bad spelling and gramma - I'm English

0
 
LVL 8

Expert Comment

by:dovholuk
ID: 6984069
jell, what is the option you're "currently" using? do you mean the filter method? if that's what you mean, there's a big advantage.

first, i'd still check the length of the string in question (i'm talking ONE word only here btw.) then i'd match all the strings (using a query) that pulled out the same COUNT of letters. After that, i'd select (From that list) which word matches exactly... the code for this would be CONSIDERABLY simple... such as:

if we have the ANAGRAMMED WORD "llib" (bill of course)

all we'd need to do is this ONE query:

SELECT
     *
FROM
     MyDictionaryTable
WHERE
     len(DictionaryWord) = len("llib") AND
     DictionaryLetterCount = "01000000100200000000000000"

this should match ALL the words in the dictionary that fit (refer to my question above about "teammate") and should produce the answer. which very well MIGHT be more than one word... bear, and bare are two other good examples of anagramed words that'll cause "problems"...

some notes:
i would put the length of each word into the table, as well as the "LetterCount" so  your dictionary table would look like:

DictionaryWord          : WordLength       : LetterCount

make sense?

this way, all the "complicated code" wouldn't be necessary, no filters nothing...

mind you, i've NOT tried it. (but this is "fun") all this stuff i'm putting out here is just "theoretical"

if you want me to give it a go i can... (just not while at work!!! ;-) ) i'll try when i get home ( 3hrs+ from now )

does that help any / make sense to anyone??? :-)

dovholuk
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6984161
Sounds like a good idea.

It's something I'd like to develope myself over the next few weeks after trying a few ideas. If you could do a bit of testing on the LetterCount idea then I would be gratefull. (V.Clever BTW!)

I'll leave the thread open for a bit and then I'll assign points.

Thanks for the great response.

Jell

0
 
LVL 8

Expert Comment

by:dovholuk
ID: 6984205
further thought...

if you have more than 9 of any one letter, you might want to use hex (so 15 letters instead of 9) or double the numbers (00=a, 01=b, 00=c, 02=d etc.) if your string is REALLY long or has a lot of the same letters... 9 letters is a lot until you start getting into phrases... then 9 letters might go quick... know what i mean?

dovholuk
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6984694
Good point.

Nosterdamus - I'm going to give you the 200 on the provision that you help me with the small filter problem.

dovholuk - I'll post a new question for 100 points - great ideas!

Csimpson/Paurths - I'll post a question fot 50 points each. Thanks for your help.

Thanks all, great thread!

Watch this space.

Regards

Jell
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6985313
Hi jell,

The idea that I had in mind is as follows:

Make two forms (Master/Child):
frmMaster will contain two fields:
InputF: TextBox (where you attach the AfterUpdate routine to)
fldTmpIndex: TextBox with it's visible property set to NO!
frmMaster will NOT be bounded to any table/field, as it is just the method to enter your input.

frmChild will be set as a continues form and will contain:
OutputF: TextBox bound to the fldWord in your table
MyIndex: TextBox bound to the index field with it's visibility property set to NO!

The data source of frmChild will be your table.

The relationship between the two forms will be:
frmMaster.fldTmpIndex <-> frmChild.MyIndex


After you enter any word in frmMaster.InputField and hit Enter/Tab (or you may rather create a button for this purpose), a routine should be executed that will do something like the follows:

Private Sub InputF_AfterUpdate()
    Me.fldTmpIndex.Value = BuildTheIndex(Me.InputF.Value)
    Me.Requery
End Sub

This will populate all the words that have the same index, as the one that makes the word in InputF, in the child form...


How does this sounds as a solution?

Nosterdamus
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6985341
Hi jell,

Sorry for the multiple posts but after I wrote the my prev comment, I realized that it could not be achieved, as you are not allowed to make a relationship between unbound forms.

therefor, the following adjustments to the above should be made:

frmMaster will contain two fields:
InputF: TextBox (where you attach the AfterUpdate routine to) UNBOUND
fldTmpIndex: TextBox with it's visible property set to NO! and BOUND to field Index in your table.

frmMaster will BE bounded to your table.

The after update routine should look like:
Private Sub InputF_AfterUpdate()
    Me.Filter = "[MyIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"
    Me.FilterOn = True
End Sub

All other instructions are the same.

HTH,

Nosterdamus
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6986068
Hi Nostre.

I'm sorry but I just can't follow what you are asking me to do. I printed of the entire question and started a new .mdb affresh.

Can you please post a new comment. Telling me exactly what to do please. Many thanks. I'm having problems with the following.

1. <The relationship between the two forms will be:
frmMaster.fldTmpIndex <-> frmChild.MyIndex>

How do I accomplish this?

2. Private Sub InputF_AfterUpdate()
   Me.Filter = "[MyIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"
   Me.FilterOn = True
End Sub

  or


Private Sub InputF_AfterUpdate()
   Me.fldTmpIndex.Value = BuildTheIndex(Me.InputF.Value)
   Me.Requery
End Sub


which one is it?

Thanks for your help but I'm getting myself a little confused I think.

Thanks

Jell
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6986266
Hi jell,

1. Create a table (tWords) with two fields:
   fldWord as text
   fldIndex as Text, Indexed allow duplicates.

2. Create an update query to update fldIndex with BuildTheIndex routine (I guess you already accomplished that).

3. Make two forms:
     a. frmMaster:
          Forms RecordSource: tWoprds
          Insert two text boxes into frmMaster:
             1. InputF as text. This field should stay unbound.
                   In the AfterUpdate event of this field, put the following routine:
                   Private Sub InputF_AfterUpdate()
                       Me.Filter = "[MyIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"
                       Me.FilterOn = True
                   End Sub
             2. TheIndex as Text. This field should be bounded (ControlSource) to fldIndex.
                   Visible property set to NO

     b. frmChild:
          Forms RecordSource: tWoprds
          Set the form view to continues, Vertical scrollbar, no div lines, no navigation bars.
          Insert two text boxes into frmChild:
             1. fldWord as text. This field should be bounded to fldWord in tWords.
             2. fldIndex as text. This field should be bounded to fldIndex in tWords.

4. Open frmMaster in design view. from the controls bar, select insert subform/subreport.
      SourceObject: frmChild
      Link child field: fldIndex (from tWords).
      Link Master field: fldIndex (from tWords).

5. Show frmMaster in FormView and enter a word in fldWord (press Enter or Tab when done)...


Note that the index should exist prior to form activation.


HTH,

Nosterdamus

p.s. I truely hope that the identation is OK....
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6986317
Hi Nostre.

Thanks for the great explanation. However, it still doesn't like the filter line on the after_update function.

It prompts me for a value for [MyIndex]. I figured that this was because the field is no longer called MyIndex but 'fldindex' instead. so I tried that.

Now it asked me for the value of whatever anagram I enter.

Please help coz I think I'm nearly there.

Thanks in advance

Regards

Jell
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6986347
Jell,

If you followed my instructions and called all you objects as I did, then This:
            1. InputF as text. This field should stay unbound.
                  In the AfterUpdate event of this field, put the following routine:
                  Private Sub InputF_AfterUpdate()
                      Me.Filter = "[MyIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"
                      Me.FilterOn = True
                  End Sub


Should read:
            1. InputF as text. This field should stay unbound.
                  In the AfterUpdate event of this field, put the following routine:
                  Private Sub InputF_AfterUpdate()
                      Me.Filter = "[TheIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"   'This line changed!!!
                      Me.FilterOn = True
                  End Sub

HTH,

Nosterdamus
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6986354
jell,

I must to go off line for the week end....

I'll wait few more minutes for your reply. after that I'll be gone till Monday.

So harry UP.
0
 
LVL 7

Accepted Solution

by:
Nosterdamus earned 300 total points
ID: 6986376
Jell,

Sorry but I have to go.

Make sure that the filter line is as follows:

Me.Filter = "[TheIndex] = '" & BuildTheIndex(Me.InputF.Value) & "'"  

That should do it... (I hope ;-))

Good luck!

Nosterdamus
0
 
LVL 12

Author Comment

by:James Elliott
ID: 6986425
Great work Nostre

increased points to 300

see u soon

regards

jell
0
 
LVL 7

Expert Comment

by:Nosterdamus
ID: 6989853
Hi jell,

Found a way to login durring weekend to see how you progress.

Glad I could help & good luck with your app.

;-)

Nosterdamus

p.s. Thanx for the extra points :-)
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

I originally created this report in Crystal Reports 2008 where there is an option to underlay sections. I initially came across the problem in Access Reports where I was unable to run my border lines down through the entire page as I was using the P…
Introduction The Visual Basic for Applications (VBA) language is at the heart of every application that you write. It is your key to taking Access beyond the world of wizards into a world where anything is possible. This article introduces you to…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
In Microsoft Access, when working with VBA, learn some techniques for writing readable and easily maintained code.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now