Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

StringMod() String Manipulation - Enhanced by PhiLho / Titan


  • Please log in to reply
77 replies to this topic
Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Another two-liner, which sometimes comes in handy, is bloating your string: add before and after each character a specified string, like `, `n or |.
CharBloat(String,left,right) {

   Loop Parse, String

      out = %out%%left%%A_LoopField%%right%

   return out

}
An application is in the random character permutation function, Scramble:
CharPerm(String) {

   String := CharBloat(String,"","`n")

   Sort String, Random

   StringReplace String, String, `n,,All

   return String

}


polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
@Laszlo, the 'Bloat' feature looks cool; I don't know where I could use it but I added it's functionality in StringMod(). I also added the 'Pattern' feature - Goyyah can explain that :p

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


AGU
  • Guests
  • Last active:
  • Joined: --
Haven't read this long thread but why not adding a replace mode that lets you replace one word or all occurences of a word inside a string.

I made s.th like this some time ago:
http://www.autohotke...opic.php?t=5365

Syntax might be s.th. like:
StringMod(String,"Replace","Word", "All")

Just a rough idea. Sorry if this has been proposed already.

_____________
Cheers
AGU

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear AGU, :)

Thanks for the suggestion.

StringMod() uses a parsing loop , and charactersers are processed one by one.
Maybe Titan will give it a try,

Thanks for posting the link. * I think this post can be a one stop resource for String Manipulation. I may collect all such useful string functions found everywhere and post it on the first post.

I encourage others to post their String Manipulation Functions here

Cheers, :)

PS: * 500+ hits and 31 posts in 72 hours :shock:
kWo4Lk1.png

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

I also added the 'Pattern' feature - Goyyah can explain that :p


A small fix is pending on Pattern feature which should be fixed soon.
Pattern will be explained it the first post & here

Regards, :D
kWo4Lk1.png

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

From Wikipedia, the free encyclopedia

An anagram (Greek ana- = "back" or "again", and graphein = "to write") is a type of word play, the result of rearranging the letters of a word or phrase to produce other words, using all the original letters exactly once. Anagrams are often expressed in the form of an equation, with the equals symbol (=) separating the original subject and the resulting anagram. ‘Earth = heart’ is an example of a simple anagram expressed in that way. In a more advanced, sophisticated form of anagramming, the aim is to ‘discover’ a result that has a linguistic meaning that defines or comments on the original subject in a humorous or ironic way; e.g., Roll in the hay = Thrill a honey (discovered by Tony Crafter). When the subject and the resulting anagram form a complete sentence, a tilde (~) is used instead of an equal sign; e.g., Semolina ~ is no meal.


What does Pattern() return?

Returns a String arranged in alphabetical order
in such a way that
the number of occurences follows each letter

Pattern is a useful function for finding Anagrams

Word1Pattern := Pattern("RACE")
Word2Pattern := Pattern("CARE")

If Word1Pattern = %Word2Pattern% ; evaluates to a logical true

because both Word1Pattern and Word2Pattern shares the same pattern "A1C1E1R1"

Pattern(_Word)
{
StringUpper,Word,_Word
Ascii=65
ReturnValue=
WordLength:=StrLen(Word)

Loop,
{
If Ascii > 90
	Break
CurrentCharacter=1
Counter=0
    Loop,
    {
         if CurrentCharacter > %WordLength%
            Break
         StringMid, Character,Word,%CurrentCharacter%,1
  	     AscChr:=Asc(Character)
         If AscChr=%Ascii%
     		    Counter+=1
         CurrentCharacter+=1
    }
    If Counter > 0
  	{
         Char:=CHR(Ascii)
         ReturnValue= %ReturnValue%%Char%%Counter%
    }
Ascii+=1
}
Return,%ReturnValue%
}

Download anagram.zip 745kb a demo of Anagram/Jumbled word finder that uses the Pattern() function efficiently.

anagram.zip contains 2 files

anagram.ahk - The GUI for retrieving Anagrams, includes Pattern()
words.db - A text file with 99,000 entries and exceeding 115,000 words

Regards, :)

PS: Please share your opinions
kWo4Lk1.png

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Pattern is useful for breaking simple substitution ciphers: In the (long enough) encrypted text, the frequencies of the letters are roughly the same as the frequencies of the letters in the used language. If you want to check anagrams, sorting the letters are simpler.
CharSort(String) {
   Loop Parse, String
      x = %x%%A_LoopField%`n
   Sort x
   StringReplace x, x, `n,,All
   Return x
}
The sorted anagrams must be equal.

Here are two shorter variants of the Pattern function.
MsgBox % CharPattern1("AutoHotKey")
MsgBox % CharPattern2("AutoHotKey")

CharPattern1(String) {
   StringUpper String, String
   Loop Parse, String
      x = %x%%A_LoopField%`n
   Sort x
   StringReplace String, x, `n,,All
   Loop Parse, String
      If(PrevChar <> A_LoopField) {
         PrevChar = %A_LoopField%
         y = %y%%count%%A_LoopField%
         count = 1
      } Else count+=1
   y = %y%%count%
   Return y
}

CharPattern2(String) {
   Loop 26
   {
      StringReplace String, String, % Chr(A_Index+64),,UseErrorLevel
      If ErrorLevel
         x := x Chr(A_Index+64) ErrorLevel
   }
   Return x
}
The first one could be faster for short inputs. It sorts the string then scans it to see if neighbor characters are different. If yes, the counter is output, telling how many copies of the previous character were found, followed by the new character. When the new character is the same as the previous was, only the counter is incremented. This function also works with non-letter, and accented characters.

The second function counts the occurrences of all 26 letters in the input, and outputs the ones, which occur at least once, followed by their counts. It is very short, but assumes the default A_StringCaseSense = OFF. To be sure, you could set StringCaseSense OFF (saving the previous value beforehand and restoring it at the end), or convert the input to upper case.

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Laszlo,

I thank you for your analysis on Pattern().

Titan had already adapted Pattern() into StringMod() which is similar to your following version:

CharPattern2(String) { 
   Loop 26 
   { 
      StringReplace String, String, % Chr(A_Index+64),,UseErrorLevel 
      If ErrorLevel 
         x := x Chr(A_Index+64) ErrorLevel 
   } 
   Return x 
}

My version of Pattern() is a line by line translation of a Foxpro UDF that I wrote many years before.
I am glad to see it AHKionized*

Your posts on this topic will be very useful for me and the future visitors.

Thanks again for sharing your wisdom.

Regards, :)

The word AHKionized was coined by BoBo guest :wink:
kWo4Lk1.png

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Titan, :)

I am writing Hangman game in which I use your StringMod.ahk unmodified, by including the following line

#Include StringMod.ahk

at the bottom of my script.

The #NoTrayIcon in StringMod.ahk is making my script's icon disappear from the taskbar.
I would be glad if you can make changes such a way that your script uses #NoTrayIcon
only when run as a standalone.

I thought of suggesting :

if A_ScriptName = StringMod.ahk
  #NoTrayIcon

but it does not work!! It still hides the Icon!

Thanks & Regards, :)
kWo4Lk1.png

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
Hello Goyyah,

The script I uploaded contained a sort of introduction message box for those who where unaware of it's uses. If you want to use the function you'll have to extract the function only which is the line starting with 'StringMod(...' up until it's closing brace '}'.

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Titan, :)

I am going to post only Hangman.ahk (and may be words.db).
Anybody want to use it will have download your StringMod.ahk

Even if I include your StringMod.ahk in the zip, any future changes to it will not be incorporated properly.

So I am planning to use in my code:

IfNotExist, StringMod.ahk
{
URLDownloadToFile,http://www.autohotkey.net/~Titan/dl/StringMod.ahk,StringMod.ahk
Reload
}

Regards, :)

PS: #Persistent ; I want to use your code unmodified
kWo4Lk1.png

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
Okay, it's safe for you to download that file and use it as an include now :)

autohotkey.com/net Site Manager

 

Contact me by email (polyethene at autohotkey.net) or message tidbit


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Dear Friends, :)

I had a requirement to chop a large HexString into manageable slices.
See my post @ Ask for Help Topic: How do I create a Binary file {Bitmap Image} with AHK Code?
I wrote function StringSlice() for BIN2AHK - Binary to AHK Code which does it and I am sharing it here.

I will feel glad if somebody optimises it..

Thank you all - Regards, :)

Function StringSlice()

Similar to AHK's StringSplit Command - However, with one difference.

String is Split, based on defined width rather than a delimiter

Example:

StringSlice("Dictionary", 3, "Var") will initialise 5 Variables: Var0 through Var4

Var0 will contain 4
Var1 will contain "Dic"
Var2 will contain "tio"
Var3 will contain "nar"
Var4 will contain "y"

; StringSlice() by A.N.Suresh Kumar aka "Goyyah"

StringSlice(String,n,ArrayName="")
{
  Global
  if ArrayName=
    ArrayName=Array
  Array0= % ArrayName "0"
  %Array0%:=1
  Ctr=1
  Array = % ArrayName Ctr

    Loop,Parse,String
       {
         SubString = % SubString A_LoopField
         %Array% := SubString
         if StrLen(SubString) >= n
           {
            Ctr+=1
            %Array0%+=1
            Array = % ArrayName Ctr
            SubString:=
           }   
      }

  Retval := %Array0%
  Return Retval
}


Edit -: the next post by Laszlo contains a better version of StringSlice()
kWo4Lk1.png

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

I will feel glad if somebody optimises it..

And also a couple of bugs are fixed
StringSlice(String,n,ArrayName="")

{

  Local k       ; Makes ArrayName global

  IfEqual ArrayName,,SetEnv ArrayName,Array



  k := Ceil(StrLen(String)/n)

  Loop %k%

    StringMid %ArrayName%%A_Index%, String, A_Index*n-n+1, n

  %ArrayName%0 = %k%

  Return k

}
Test it with
x := StringSlice("Dictionary", 3)

ListVars

MsgBox %x%



x := StringSlice("Dictionar", 3, "Var")

ListVars

MsgBox %x%



PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Looks like a complete rewriting... :-D
I would use k := StrLen(String) // n, but it is probably a matter of taste/habits. Same for index, I would have written (A_Index - 1) * n + 1, showing better the logic (IMHO).
And using SetEnv to avoid having two lines is a bit less readable.
But overall, code is very clever, and the idea is a good one. I regretted sometime that Loop Parse didn't has such functionnality, now we have it...
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")