AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

inStr question
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sat Apr 25, 2009 8:47 pm    Post subject: inStr question Reply with quote

I'm trying to use inStr to find the last occurance of a backslash ("\"). However, I want to omit the last character. The goal is to navigate one folder upward (toward the root).

Code:
Folder := "C:\FolderA\FolderB\"

;works using StringGetPos
StringGetPos, index, Folder, % "\", R, 1
index++

if (index)
{
    Folder := subStr(Folder, 1, index)

    ;outputs "C:\FolderA\"
    MsgBox, % Folder
}


Code:
Folder := "C:\FolderA\FolderB\"

;doesn't work using inStr (index = 0)
index := inStr(Folder, "\", false, -1)

if (index)
{
    Folder := subStr(Folder, 1, index)
    MsgBox, % Folder
}

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
sinkfaze



Joined: 19 Mar 2008
Posts: 2721
Location: the tunnel(?=light)

PostPosted: Sat Apr 25, 2009 9:10 pm    Post subject: Reply with quote

The value for index is going to be the count including the character you're trying to omit, no?

Code:
Folder := "C:\FolderA\FolderB\"

index := inStr(Folder,"\",false,0)

if (index)
{
    Folder := subStr(Folder,1,(index - 1))
    MsgBox, % Folder
}

_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sat Apr 25, 2009 9:39 pm    Post subject: Reply with quote

sinkfaze wrote:
The value for index is going to be the count including the character you're trying to omit, no?

I'm not sure I understand the question, so I'm not really sure how to respond, sorry.

The goal is to transverse up one directory. I want it to work regardless if the directory has a trailing "\" or not. Your example doesn't output what I need because it only removes the trailing "\". I want it to remove the entire directory - resulting in "C:\FolderA\".
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
SKAN



Joined: 26 Dec 2005
Posts: 7187

PostPosted: Sat Apr 25, 2009 10:04 pm    Post subject: Reply with quote

animeaime wrote:
The goal is to transverse up one directory.


I would do it like

Code:
Folder := "C:\FolderA\FolderB\"
DllCall( "shlwapi\PathRemoveBackslashA", Str,Folder )
SplitPath,Folder,,Folder
MsgBox, % Folder "\"

_________________
Suresh Kumar A N
Back to top
View user's profile Send private message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sat Apr 25, 2009 10:11 pm    Post subject: Reply with quote

ic. Very nice. One question - what's the difference between using a DllCall and simply removing the backslash?

Code:
Folder := "C:\FolderA\FolderB"

if subStr(Folder, 0) = "\"
    StringTrimRight, Folder, Folder, 1

SplitPath,Folder,,Folder
MsgBox, % Folder "\"

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
sinkfaze



Joined: 19 Mar 2008
Posts: 2721
Location: the tunnel(?=light)

PostPosted: Sat Apr 25, 2009 10:57 pm    Post subject: Reply with quote

animeaime wrote:
I'm not sure I understand the question, so I'm not really sure how to respond, sorry.


That's okay, I didn't read your question correctly.

SKAN pretty much covered my answer. AFAIK InStr doesn't have the "looking" ability of StringGetPos, so you'd have to do something like this if you know it's always going to be the 2nd occurrence from the right:

Code:
Folder := "C:\FolderA\FolderB\"

index := InStr(SubStr(Folder,1,InStr(Folder, "\", false, 0) - 1),"\", false, 0)

if (index)
{
    Folder := subStr(Folder, 1, index)
    MsgBox, % Folder
}


Not too confusing, huh? Rolling Eyes

EDIT: You could also use RegExMatch:

Code:
Folder := "C:\FolderA\FolderB\"

RegExMatch(Folder,"^(?P<Folder>C:\\.*?\\)",Root)

if (RootFolder)
  MsgBox, % RootFolder

_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.


Last edited by sinkfaze on Sat Apr 25, 2009 11:08 pm; edited 1 time in total
Back to top
View user's profile Send private message
rulfzid



Joined: 27 Nov 2008
Posts: 62

PostPosted: Sat Apr 25, 2009 11:04 pm    Post subject: Reply with quote

Using regular expressions:

Code:
folder := "C:\folderA\folderB\"
MsgBox % GetOneDirUp( folder )

GetOneDirUp( folder ) {
   RegExMatch( folder, "(.*)(?=\\.+?)(?:\\(?!=.))?", up_a_dir )
   if not up_a_dir ; we're already at a drive
      return 0
   return up_a_dir1
}
Back to top
View user's profile Send private message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sat Apr 25, 2009 11:35 pm    Post subject: Reply with quote

Thanks for all the feedback. I think I'm going to stick with my current design. The others seem more complicated than they are worth. I like SKAN's solution, but no matter how many times I look at it, it's not very intuitive for me. I don't think to use SplitPath like that, so it will only cause confusion reading the code.

As far as the RegExes go, I think they are overkill. It's been mentioned that RegEx should be avoided, when possible, due to performance. Granted, performance isn't really an issue here, but I think RegEx only complicates things.

Sorry for the fuss. It seems that the answer to my question is that inStr can't be used how I want, which is a shame. I think it would be really nice to have inStr be a wrapper for the StringGetPos command, but at least we have the StringGetPos command to use. Thanks again for all the ideas.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
sinkfaze



Joined: 19 Mar 2008
Posts: 2721
Location: the tunnel(?=light)

PostPosted: Sun Apr 26, 2009 12:04 am    Post subject: Reply with quote

animeaime wrote:
As far as the RegExes go, I think they are overkill. It's been mentioned that RegEx should be avoided, when possible, due to performance.


To each their own, but in this case it would take quite a tremendous amount of repetitions to bear out a significant difference in performance, IMO:

Code:
Folder := "C:\FolderA\FolderB\"

QPC()
StringGetPos, index, Folder, % "\", R, 1
index++
if (index)
    Folder := subStr(Folder, 1, index)
T1 := QPC()
QPC()
RegExMatch(Folder,"^(?P<Folder>C:\\.*?\\)",Root)
if (RootFolder)
   Folder := RootFolder
T2 := QPC()

MsgBox % "StringGetPos: " T1 "`nRegExMatch: " T2 ""

QPC() {
   Static Freq, LastCount
   If !Freq
      DllCall("QueryPerformanceFrequency", "Int64*", Freq)
   DllCall("QueryPerformanceCounter", "Int64*", Count)
   Return (Count-LastCount)/Freq, LastCount:=Count
}


My results averaged over 50 runs:

results wrote:
StringGetPos: 0.000019
RegExMatch: 0.000032

_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sun Apr 26, 2009 12:14 am    Post subject: Reply with quote

@sinkfaze

Well, for your RegEx, it doesn't work when there are more than two subfolders.

Code:
Folder := "C:\FolderA\FolderB\FolderC\"

RegExMatch(Folder,"^(?P<Folder>C:\\.*?\\)",Root)

;outputs "C:\FolderA\"
if (RootFolder)
  MsgBox, % RootFolder


The other RegEx looks too complicated for the problem at hand - in light of the two non-RegEx solutions already posted - like you said, personal preferance. I like code that I can read - this is one of my, personal, requirements. If I can't read it and make sense of it quickly, then I rewrite the code in a more readable form. Of course, I make no quarantee that someone else can read my code Very Happy.
_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
rulfzid



Joined: 27 Nov 2008
Posts: 62

PostPosted: Sun Apr 26, 2009 12:17 am    Post subject: Reply with quote

In fact, comparing stringgetpos, splitpath, and regexmatch:

Code:
folder := "C:\foldera\folderb\"
num = 10000


TickCount()

Loop % num
   f := GetOneDirUp_splitpath( folder )

splitpath_time := TickCount()/1000

Loop % num
   f := GetOneDirUp_regex( folder )

regex_time := TickCount()/1000

Loop % num
   f := GetOneDirUp_stringgetpos( folder )
   
stringgetpos_time := TickCount()

Msgbox % "SplitPath: " splitpath_time " seconds`nRegex: " regex_time " seconds`nStringGetPos: " stringgetpos_time " seconds"
clipboard := "SplitPath: " splitpath_time " seconds`nRegex: " regex_time " seconds`nStringGetPos: " stringgetpos_time " seconds"


GetOneDirUp_regex( folder ) {
   RegExMatch( folder, "(.*)(?=\\.+?)(?:\\(?!=.))?", up_a_dir )
   if not up_a_dir ; we're already at a drive
      return 0
   return up_a_dir1
}

GetOneDirUp_splitpath( folder ) {
   if subStr(Folder, 0) = "\"
    StringTrimRight, Folder, Folder, 1
   SplitPath,Folder,,Folder
   return folder
}

GetOneDirUp_stringgetpos( folder ) {
   StringGetPos, index, Folder, % "\", R, 1
   index++   
   if index
       return subStr(Folder, 1, index)   
}

TickCount() {
   Static LastCount
   Return (A_TickCount-LastCount)/1000, LastCount := A_TickCount
}


Setting num to 10000 gives me:
Quote:
SplitPath: 0.000031 seconds
Regex: 0.000250 seconds
StringGetPos: 0.063000 seconds


Setting num to 100000 gives me:
Quote:
SplitPath: 0.000625 seconds
Regex: 0.002875 seconds
StringGetPos: 0.625000 seconds


Splitpath is consisently the fastest, but unless you're running millions of these, you're not seeing any performance differences between splitpath and regex. StringGetPos, weirdly, is slower by a factor of several hundred. I guess mainly I'm pointing out that regular expressions are actually pretty darn fast.

@Sinkfaze

I wonder what causes the differences in performance between your regex and mine. I'd guess it's using the named subpatterns?
Back to top
View user's profile Send private message
sinkfaze



Joined: 19 Mar 2008
Posts: 2721
Location: the tunnel(?=light)

PostPosted: Sun Apr 26, 2009 12:27 am    Post subject: Reply with quote

animeaime wrote:
Well, for your RegEx, it doesn't work when there are more than two subfolders.


Very true, I was making a solution limited to only two instances. RegExReplace would make it more adapatable to more situations:

Code:
Folder := "C:\FolderA\FolderB\FolderC\"

MsgBox, % RegExReplace(Folder,"(?P<Folder>C:\\[\w\s-]+).*","${Folder}\")

_________________
Try Quick Search for Autohotkey or see the tutorial for newbies.
Back to top
View user's profile Send private message
animeaime



Joined: 04 Nov 2008
Posts: 1046

PostPosted: Sun Apr 26, 2009 12:27 am    Post subject: Reply with quote

@rulfzid: You forgot to divide by 1000 for the StringGetPos

Code:
folder := "C:\foldera\folderb\"
num = 10000


TickCount()

Loop % num
   f := GetOneDirUp_splitpath( folder )

splitpath_time := TickCount()/1000

Loop % num
   f := GetOneDirUp_regex( folder )

regex_time := TickCount()/1000

Loop % num
   f := GetOneDirUp_stringgetpos( folder )
   
stringgetpos_time := TickCount()/1000

Msgbox % "SplitPath: " splitpath_time " seconds`nRegex: " regex_time " seconds`nStringGetPos: " stringgetpos_time " seconds"
clipboard := "SplitPath: " splitpath_time " seconds`nRegex: " regex_time " seconds`nStringGetPos: " stringgetpos_time " seconds"


GetOneDirUp_regex( folder ) {
   RegExMatch( folder, "(.*)(?=\\.+?)(?:\\(?!=.))?", up_a_dir )
   if not up_a_dir ; we're already at a drive
      return 0
   return up_a_dir1
}

GetOneDirUp_splitpath( folder ) {
   if subStr(Folder, 0) = "\"
    StringTrimRight, Folder, Folder, 1
   SplitPath,Folder,,Folder
   return folder
}

GetOneDirUp_stringgetpos( folder ) {
   StringGetPos, index, Folder, % "\", R, 1
   index++   
   if index
       return subStr(Folder, 1, index)   
}

TickCount() {
   Static LastCount
   Return (A_TickCount-LastCount)/1000, LastCount := A_TickCount
}

_________________
As always, if you have any further questions, don't hesitate to ask.

Add OOP to your scripts via the Class Library. Check out my scripts.
Back to top
View user's profile Send private message Send e-mail
Sean



Joined: 12 Feb 2007
Posts: 2224

PostPosted: Sun Apr 26, 2009 12:33 am    Post subject: Reply with quote

In this case, RegEx is not that un-intuitive, really verbatim to what we actually carried out.
Code:
Folder := "C:\FolderA\FolderB\FolderC\"
;Folder := "C:\FolderA\FolderB\FolderC"
RegExMatch(Folder,"^.*\\(?=[^\\]+\\?$)",Root)
MsgBox % Root
Back to top
View user's profile Send private message
rulfzid



Joined: 27 Nov 2008
Posts: 62

PostPosted: Sun Apr 26, 2009 12:33 am    Post subject: Reply with quote

Doh! Embarassed

You are correct.

But my assertion that you'd need to be running these millions of times for any significant difference still stands.

Apologies for incorrectly jumping guns.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group