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
polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
I don't see the reason for StringSlice(). If you really need it, a few simple lines would do it:

AutoTrim, Off
string =example text sliced into bits

Loop, Parse, string
	If !Mod(A_Index, 3) {
		sub = %sub%%A_LoopField%
		MsgBox [%sub%] ; your code for the substring goes here
		sub := ""
	} Else sub =%sub%%A_LoopField%

autohotkey.com/net Site Manager

 

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


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

I would use k := StrLen(String) // n

StrLen(String) // n = Floor(StrLen(String)/n) and we need Ceil here, what you could get with (StrLen(String)+n-1) // n.

I would have written (A_Index - 1) * n + 1, showing better the logic (IMHO).

But it is 2 chars longer, which is a horrible loss of resources. :lol:

And using SetEnv to avoid having two lines is a bit less readable.

It will be replaced with a same-line construct "if (cond) command", when it gets to AHK.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Titan: your code does not handle the slack, the last block of chars, if it is shorter than n.

Also, you assume that the blocks are processed sequentially. The main advantage of StringSplit and StringSlice is that they facilitate random access to the blocks.

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
I see. Well your solution would be the best option for slicing strings then.

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 Laszlo, :)

I Thank you very much for the Optimised Version. (also for fixing the bugs). I require StringSlice() for many more tasks. :D

Thanks to PhiLho & Titan for throwing more light on the subject.

Regards, :)
kWo4Lk1.png

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005

The main advantage of StringSplit and StringSlice is that they facilitate random access to the blocks.

Good idea, here is my take, reformatted to be included in my private collection of useful string functions:
SliceString(_string, _sliceSize, _arrayName="")
{
    local k       ; Makes created array global

    If (_arrayName = "")
    {
        _arrayName = Array
    }

    k := Ceil(StrLen(_string) / _sliceSize)
    Loop %k%
    {
        StringMid %_arrayName%%A_Index%, _string, (A_Index - 1) * _sliceSize + 1, _sliceSize
    }
    %arrayName%0 := k

    Return k
}

; Thin wrapper, just avoids to make the maths each time
GetStringSlice(_string, _sliceSize, _sliceIndex)
{
    local slice

    StringMid slice, _string, (_sliceIndex - 1) * _sliceSize + 1, _sliceSize

    Return slice
}

x := SliceString("Dictionary", 3)
ListVars
MsgBox %x%

x := SliceString("Dictionar", 3, "var")
ListVars
MsgBox %x%

slice := GetStringSlice("Dictionary", 3, 2)
MsgBox %slice%
slice := GetStringSlice("Dictionary", 3, 4)
MsgBox %slice%
Of course, you were right for the Ceil vs. Floor, my proposal was stupid.
I make horrible "waste of resources", adding lines and spaces, and even unnecessary braces... :-P But that's my choice, I dropped cramped styles a long time ago... And I like my function names to start with a verb (a not so uncommon choice, even official in Java).
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")

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

I dropped cramped styles a long time ago... And I like my function names to start with a verb

For short functions the style does not really matter. For complex programs I often need to separate blocks, sub-blocks, sub-sub-blocks… You quickly run out of options: Indentations, empty lines, block comments, separator lines. If I define functional blocks as separate functions, I often have to turn pages and find my way back to the original place after several levels of indirections. This is why I write short elementary tasks as compact as possible and use separators only between them. (I dropped this style, when – long ago, for a short time – my performance was measured by the number of uncommented lines of code. My employer abandoned this nonsense when I showed that my 20-line function was twice faster and much easier to maintain than the 500-line module it replaced.)

Of course, this is personal preference, like naming. The company coding standard required the use of informative, hierarchical variable names, like MeasurementSubsystem_SignalQuality_DataAnalysis_FastHartleyTransform_TimeVariable. I used "t" instead, and a header explaining its meaning, and the function was called, outrageously, FHT.

If you build a library, you sort function names for finding easier, what you need. It is more convenient to have all the string functions next to each other, like StringSlice, StringSort, StringSplit… than having all the GetSomething, SortSomething functions together. Especially, since String, Int, Num, Bin, List are more or less standardized, but Get, Read, Acquire, Peek, Extract could be synonymous, and you have to browse the list at all these places.

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

Function LDOM() has been reposted Here...

Sorry for any inconvenience. Regards :)
kWo4Lk1.png

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
Thats more to do with time rather than strings :?:

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 have a requirement for which I wrote the following

Phrase:="The Quick Brown Fox Jumps Over The Lazy Dog"
MsgBox, % SubWord(Phrase,6,A_Space) ; Returns "Over"
Return

SubWord(Phrase,Num,Delimiter="") {
 Loop,Parse,Phrase, %Delimiter%
      {   
       RWord:=A_LoopField
       Index:=A_Index
       IfEqual,A_Index,%Num%,Break
      }
 IfLess,Index,%Num%, Return, ""
 Return RWord
}

Thought this was interesting enough to be included something like:

StringMod(String, "Subword", 6, A_Space)

Regards, :)
kWo4Lk1.png

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
I liked the idea, but I couldn't resist. :) So here is a tweak (50% less lines of code ;)
SubWord(Phrase,Num,Delimiter="") { 
    Loop,Parse,Phrase, %Delimiter% 
        IfEqual,A_Index,%Num%, Return A_LoopField
    Return 
  }

Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

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

here is a tweak (50% less lines of code ;)


Oh Yes! :D Many thanks for the tweak toralf!
The function was only 5 minutes old when I posted it.. Guess I am very tired with sleepless nights..
.. And I love this forum .. getting such instant optimisations!

Regards, :)
kWo4Lk1.png

polyethene
  • Members
  • 5519 posts
  • Last active: May 17 2015 06:39 AM
  • Joined: 26 Oct 2012
This is even shorter:
subword(str, n, del = "") {

	StringSplit, w, str, %del%

	Return, w%n%	

}


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

This is even shorter:

subword(str, n, del = "") {
	StringSplit, w, str, %del%
	Return, w%n%	
}


Yes! I thought of it .. but wanted to avoid it because:

This function is meant for a dictionary where the meaning can run up to 2k ...
and I am concerned only with the first 9 words ..

To make it clear .. I am creating a English Dictionary DB where the user can subsearch any of the first 9 words in the meaning!

Regards, :)
kWo4Lk1.png

PhiLho
  • Moderators
  • 6850 posts
  • Last active: Jan 02 2012 10:09 PM
  • Joined: 27 Dec 2005
Conceptually, I prefer Goyyah & toralf's way than your, Titan. That's because on a long string, the StringSplit will have to find and allocate all the variables, even if only the first is requested. While the Loop Parse stops as soon as it reached its goal, and drops intermediary results.

Goyyah, why do you hate so much space? I like to put a space after commas and around = or :=, I find it easier on the eye, code breathes... :-)
Just a thought, coding rules are very subjective, of course.

[EDIT] For the record, I just saw Goyyah's post above. He thinks like me... :-)
Posted Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")