Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 22nd November 2011, 06:14   #1  |  Link
vampiredom
Registered User
 
Join Date: Aug 2008
Posts: 233
SplitFilename() function for splitting filenames [2011/11/22]

This is loosely related to this thread and I thought of posting there but I did not want to veer too much off-topic. So, here it is...

Code:
######################################################################################################################
# SplitFilename()
# 2011/11/22
# a function for splitting filenames into different parts. The "which" parameter determines which parts are returned
#
# parameter:    filename (string)
#               -----------------
#               This should be a filename or a path. Both forward slashes and backslashes are allowed
#               It works with both files and folders, relative and absolute paths.
#               If the supplied string is a path to a folder, it should end in a / or \
#
#               which (integer)
#               ---------------
#               This parameter should be an integer between -2 and 4, and returns the following result:
#               Example: C:\Folder\Subfolder\Filename.ext
#               |
#               | -2 --> drive + folder                         C:\Folder\Subfolder\
#               | -1 --> drive + folder + basename              C:\Folder\Subfolder\Filename
#               |  0 --> basename + ext                         Filename.ext
#               |  1 --> drive                                  C:
#               |  2 --> folder                                 \Path\Subfolder\
#               |  3 --> basename                               Filename
#               |  4 --> ext                                    .ext
#
#               An empty string is returned if there is no appropriate result
#               (such as a relative path, a filename with no path or a file with no extension)
#               Values outside of the range of -2 to 4 also return an empty string
#               When returned, drive letter always ends with : and extension always begins with a .
#
#######################################################################################################################

Code:
function SplitFilename(
\ string filename,
\ int    which
\ ) {
        
        # first get the extension. If there is a slash after the ".", then it is not an extension but a dotted folder name
        ext = RightStr(filename, FindStr(RevStr(filename), "."))
        ext = (FindStr(ext, "/") > 0 || FindStr(ext, "\") > 0) ? "" : ext
        
        # now determine drive name, folder name, and file basename
        # allow both "/" and "\" for folder names
        drive       = LeftStr(filename, FindStr(filename, ":"))
        dir1        = (Findstr(filename, "\") >  0) ? LeftStr(filename, StrLen(filename) - FindStr(RevStr(filename), "\") +1) : ""
        dir2        = (Findstr(filename, "/") >  0) ? LeftStr(filename, StrLen(filename) - FindStr(RevStr(filename), "/") +1) : ""
        dir         = (StrLen(dir1) > StrLen(dir2)) ? dir1 : dir2
        
        folder      = (StrLen(dir) > 0) ? RightStr(dir, StrLen(dir) - StrLen(drive)) : ""
        basename    = MidStr(filename, StrLen(drive)+StrLen(folder)+1, StrLen(filename) - StrLen(drive) - StrLen(folder) - StrLen(ext))
        
        # copy extension to filename and clear extension for filenames that begin with .
        isDotFile = (ext != "" && basename == "") ? true : false
        dotBase  = ext
        basename = (isDotFile) ? dotBase : basename
        ext      = (isDotFile) ? ""      : ext

        
        (filename == "") ? ""
        \ : (which    == -2)  ? drive + folder
        \ : (which    == -1)  ? drive + folder + basename
        \ : (which    ==  0)  ? basename + ext
        \ : (which    ==  1)  ? drive
        \ : (which    ==  2)  ? folder
        \ : (which    ==  3)  ? basename
        \ : (which    ==  4)  ? ext
        \ : ""
}
A quick way to test exactly how this works can be accomplished by running a script like this:

Code:
f = "C:\Folder\Subfolder\Filename.ext"

BlankClip()
subtitle("---> " + f,                   font="Courier New", y= 10, text_color=$FFFF00)
subtitle("-2 = " + Splitfilename(f,-2), font="Courier New", y= 40, text_color=$DDDDDD)
subtitle("-1 = " + Splitfilename(f,-1), font="Courier New", y= 70, text_color=$DDDDDD)
subtitle(" 0 = " + Splitfilename(f, 0), font="Courier New", y=100, text_color=$DDDDDD)
subtitle(" 1 = " + Splitfilename(f, 1), font="Courier New", y=130, text_color=$DDDDDD)
subtitle(" 2 = " + Splitfilename(f, 2), font="Courier New", y=160, text_color=$DDDDDD)
subtitle(" 3 = " + Splitfilename(f, 3), font="Courier New", y=190, text_color=$DDDDDD)
subtitle(" 4 = " + Splitfilename(f, 4), font="Courier New", y=220, text_color=$DDDDDD)

Last edited by vampiredom; 22nd November 2011 at 21:17. Reason: implemented suggested changes
vampiredom is offline   Reply With Quote
Old 22nd November 2011, 12:22   #2  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,377
Quote:
Originally Posted by vampiredom View Post
Code:
function SplitFilename(
\ string filename,
\ int    which
\ ) {

        which = Default(which, 0)
        filename = default(filename, "")
        ...        
        folder      = RightStr(dir, StrLen(dir) - StrLen(drive))
        basename    = MidStr(filename, StrLen(dir)+1, StrLen(filename) - StrLen(dir) - StrLen(ext))
 ...
}
The 'default' lines are redundant, since you have made the parameters mandatory. (Remember what I said yesterday?)
To make 'which' optional (it wouldn't make sense for 'filename' to be optional), put quotes around the name in the function header.

A filename with a drive and no folder (eg "C:file.ext", meaning use current folder on drive C) will give a negative length in RightStr, producing an error. You need to do this:
Code:
        folder      = StrLen(dir)>0 ? RightStr(dir, StrLen(dir) - StrLen(drive)) : ""
        basename    = MidStr(filename, StrLen(drive)+StrLen(folder)+1, StrLen(filename)-StrLen(drive)-StrLen(folder)-StrLen(ext))
Other observations:
- you don't need to use CHR(92) instead of "\", since \ has no special meaning in Avisynth;
- not sure if it is correct to regard filenames starting with a '.' as having no extension, eg a file called ".avs" will still be played by WMP as an Avisynth script.
__________________
GScript and GRunT - complex Avisynth scripting made easier

Last edited by Gavino; 22nd November 2011 at 12:57. Reason: add code for setting 'basename'
Gavino is offline   Reply With Quote
Old 22nd November 2011, 14:09   #3  |  Link
vampiredom
Registered User
 
Join Date: Aug 2008
Posts: 233
Quote:
The 'default' lines are redundant, since you have made the parameters mandatory. (Remember what I said yesterday?)
Ha, yes. Actually, they were optional... then I changed it but forgot to remove the 'defaults'. Fixed. [I had it use GetWorkingPath() from [GetSystemEnv.dll] as default filename, for example, in case this being optional sounded completely crazy.]

Quote:
you don't need to use CHR(92) instead of "\"
I know that. It's my text editor that gets a little confused with "\", so I avoid it. I have now restored the "\" for others' reading pleasure.

Quote:
not sure if it is correct to regard filenames starting with a '.' as having no extension, eg a file called ".avs" will still be played by WMP as an Avisynth script.
It seems to me that a file called ".avs" does have a filename but not an extension. It is kind of an odd situation.

Quote:
A filename with a drive and no folder (eg "C:file.ext", meaning use current folder on drive C) will give a negative length in RightStr, producing an error. You need to do this:
Excellent. I had not thought about that case. Thank you. Your suggested change has been implemented.

Last edited by vampiredom; 22nd November 2011 at 14:54.
vampiredom is offline   Reply With Quote
Old 22nd November 2011, 21:11   #4  |  Link
vampiredom
Registered User
 
Join Date: Aug 2008
Posts: 233
WinPath(), BSDPath() and StrReplace()

As a "companion" to SplitFilename(), I wrote WinPath(), which translates / to \, and BSDPath(), which does the opposite. This is a way of converting filename strings to/from Windows <-> UN*X-style paths. This may be handy for interfacing with programs that provide or prefer one over the other.

In addition, the StrReplace() function provided by Gavino that powers the pathname translation can be used as a general string replacement function.

** EDIT ** Thanks to Gavino and IanB for the massive improvements here

Code:
function WinPath(string path) {
        path.StrReplace("/", "\")
}

function BSDPath(string path) {
        path.StrReplace("\", "/")
}

function StrReplace(string s, string find, string replace) {
        i = s.FindStr(find)
        return (i == 0 ? s : s.LeftStr(i-1)+replace+s.RightStr(StrLen(s)-Strlen(find)-i+1).StrReplace(find, replace))
}
so ... an example of these in action (and to test them) could be:

Code:
a  = "C:/path/file.ext"
a2 = a.WinPath()
a3 = a2.StrReplace("C:\path", "C:\windows")
a4 = a3.StrReplace("C:\windows\", "\relative\to\root\")
a5 = a4.BSDPath()
a6 = a5.StrReplace("/", " ").StrReplace("l", "!").StrReplace("o", "*").StrReplace(".", ", ")

BlankClip()
subtitle("---> " + a,   font="Courier New", y= 10, text_color=$FFFF00)
subtitle("---> " + a2,  font="Courier New", y= 40, text_color=$DDDDDD)
subtitle("---> " + a3,  font="Courier New", y= 70, text_color=$DDDDDD)
subtitle("---> " + a4,  font="Courier New", y=100, text_color=$DDDDDD)
subtitle("---> " + a5,  font="Courier New", y=130, text_color=$DDDDDD)
subtitle("---> " + a6,  font="Courier New", y=160, text_color=$DDDDDD)

Last edited by vampiredom; 23rd November 2011 at 00:53. Reason: used IanB's mod of Gavino's string replacement function
vampiredom is offline   Reply With Quote
Old 22nd November 2011, 21:24   #5  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,377
Quote:
Originally Posted by vampiredom View Post
the ReplaceString() function that powers the pathname translation can be used as a general string replacement function, replacing up to 400 instances per string. (I know I could use Gavino's plugin for while(){} syntax, but I wanted this to be all native AviSynth code and I figured no path would ever have more than 400 slashes)
You could do it much more concisely and efficiently, and with unlimited replacements, with a recursive function. Here's what I use:
Code:
function StrReplace(string s, string find, string replace) {
  i = s.FindStr(find)
  return (i == 0 ? s : s.LeftStr(i-1)+replace+s.RightStr(StrLen(s)-Strlen(find)-i+1).StrReplace(find, replace))
}
__________________
GScript and GRunT - complex Avisynth scripting made easier

Last edited by Gavino; 22nd November 2011 at 21:26.
Gavino is offline   Reply With Quote
Old 22nd November 2011, 21:36   #6  |  Link
vampiredom
Registered User
 
Join Date: Aug 2008
Posts: 233
Quote:
more concisely and efficiently, and with unlimited replacements, with a recursive function
Awesome. I do this kind of thing in other scripting languages. I don't know why I assumed it was impossible in AviSynth. Thanks so much. Big improvement and you taught me something that will be invaluable to me for future scripting.

The script at top has been edited include these improvements.
vampiredom is offline   Reply With Quote
Old 22nd November 2011, 22:33   #7  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,168
MidStr(string, int pos [, int length]) with defaulted length is often a more useful choice than RightStr.
Code:
function StrReplace(string s, string find, string replace) {
  i = s.FindStr(find)
  return (i == 0 ? s : s.LeftStr(i-1)+replace+s.MidStr(Strlen(find)+i).StrReplace(find, replace))
}
IanB is offline   Reply With Quote
Old 22nd November 2011, 23:04   #8  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,377
Quote:
Originally Posted by IanB View Post
MidStr(string, int pos [, int length]) with defaulted length is often a more useful choice than RightStr.
Thanks, Ian - I'd overlooked that option.
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 23rd November 2011, 00:54   #9  |  Link
vampiredom
Registered User
 
Join Date: Aug 2008
Posts: 233
Quote:
MidStr(string, int pos [, int length])
Excellent again. Now implemented above. Thanks!
vampiredom is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 01:13.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.