AutoHotkey Community

It is currently May 26th, 2012, 5:45 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: inStr question
PostPosted: April 25th, 2009, 8:47 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 9:10 pm 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5479
Location: the tunnel(?=light)
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
}

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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 9:39 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 10:04 pm 
Offline
User avatar

Joined: December 26th, 2005, 4:40 pm
Posts: 8776
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 ""

_________________
URLGet - Internet Explorer based Downloader
StartEx - Portable Shortcut Link


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 10:11 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 10:57 pm 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5479
Location: the tunnel(?=light)
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? :roll:

EDIT: You could also use RegExMatch:

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

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

if (RootFolder)
  MsgBox, % RootFolder

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


Last edited by sinkfaze on April 25th, 2009, 11:08 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 11:04 pm 
Offline

Joined: November 27th, 2008, 9:44 am
Posts: 62
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
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 25th, 2009, 11:35 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:04 am 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5479
Location: the tunnel(?=light)
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

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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:14 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
@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 :D.

_________________
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:17 am 
Offline

Joined: November 27th, 2008, 9:44 am
Posts: 62
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?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:27 am 
Offline
User avatar

Joined: March 19th, 2008, 12:43 am
Posts: 5479
Location: the tunnel(?=light)
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}")

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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:27 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
@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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:33 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 26th, 2009, 12:33 am 
Offline

Joined: November 27th, 2008, 9:44 am
Posts: 62
Doh! :oops:

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.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 25 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: batto, BrandonHotkey, G. Sperotto, gamax92, Google Feedfetcher, Miguel, notsoobvious, rbrtryn and 72 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group