Page 1 of 1
Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 12:54 pm
by Dreamland Fantasy
Hi there,
This procedure appends a sequential number to a file name in the format of "filename (n).jpg", where 'n' is the added number from 2 upwards. This is handy when e.g. copying files so that pre-existing files are not overwritten.
Code: Select all
Procedure.s AddSequentialNumber(FileName$)
Protected Directory$, Extension$, i, j, n
Directory$ = GetPathPart(FileName$)
Extension$ = GetExtensionPart(FileName$)
FileName$ = GetFilePart(FileName$, #PB_FileSystem_NoExtension)
If Len(FileName$) > 4
For i = Len(FileName$) To 1 Step -1
If Mid(FileName$, i, 1) = "("
For j = i To Len(FileName$)
If Mid(FileName$, j, 1) = ")"
n = Val(Mid(FileName$, i + 1, j - i - 1))
If n
FileName$ = RemoveString(FileName$, Mid(FileName$, i, j - i + 1), #PB_String_NoCase, i, 1)
Break 2
EndIf
EndIf
Next
EndIf
Next
EndIf
If n
FileName$ = InsertString(FileName$, "(" + Str(n + 1) + ")", i)
Else
FileName$ = FileName$ + " (2)"
EndIf
FileName$ = Directory$ + FileName$
If Extension$
FileName$ + "." + Extension$
EndIf
If FileSize(FileName$) >= 0 ; Checks existence of file
FileName$ = AddSequentialNumber(FileName$)
EndIf
ProcedureReturn FileName$
EndProcedure
;- Test code below
FileName$ = OpenFileRequester("Select a file", "", "", 0)
For i = 1 To 10
CopyFile(FileName$, AddSequentialNumber(FileName$))
Next
Kind regards,
Francis
Re: Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 1:05 pm
by Dude
Works well. I tried to break it and make it destroy a bunch of existing files, and it didn't. Good job!

Re: Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 1:10 pm
by Dreamland Fantasy
Dude wrote:Works well. I tried to break it and make it destroy a bunch of existing files, and it didn't. Good job!

Thanks for testing it out.
Kind regards,
Francis
Re: Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 2:03 pm
by Trond
Interesting. I just wrote something similar, so I wanted to compare it with your version. Which was a good idea, because it turned out neither of them worked optimally when the file didn't have an extension. (They added an extra dot.)
Also, my version started with the number 1, which, when thinking about it, isn't logical, as the original file would be number 1. So I changed it to start at 2.
My improved code:
Code: Select all
Procedure.s SafeFilename(OutFileName.s)
NewFileName.s = OutFileName
I = 1
While FileSize(NewFileName) <> -1
I + 1
NewFileName = GetPathPart(OutFileName) + GetFilePart(OutFileName, #PB_FileSystem_NoExtension) + " (" + Str(I) + ")"
Extension.s = GetExtensionPart(OutFileName)
If Extension
NewFileName + "." + Extension
EndIf
Wend
If OutFileName <> NewFileName
;PrintN("Output file exists, using another filename: " + NewFileName)
OutFileName = NewFileName
EndIf
ProcedureReturn OutFileName
EndProcedure
;- Test code below
FileName$ = OpenFileRequester("Select a file", "", "", 0)
For i = 1 To 10
Debug AddSequentialNumber(FileName$)
Debug SafeFilename(FileName$)
;CopyFile(FileName$, SafeFilename(FileName$))
Debug ""
Next
Re: Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 4:59 pm
by Dreamland Fantasy
Thanks Trond for pointing out the bug if there was no extension. I've updated my code above to fix that.
I noticed with your code, if you use a file name such as "filename (2).jpg" then your code generates a file name of "filename (2) (2).jpg" instead of the next number up (e.g. "filename (3).jpg").
Kind regards,
Francis
Re: Adding sequential numbers to a file name
Posted: Sat Jun 02, 2018 7:28 pm
by davido
@Dreamland Fantasy,
Works well, thank you for sharing.
Re: Adding sequential numbers to a file name
Posted: Wed Jun 20, 2018 9:38 pm
by Dreamland Fantasy
Thanks for trying it out davido.
Kind regards,
Francis
Re: Adding sequential numbers to a file name
Posted: Thu Jun 21, 2018 12:34 pm
by NicTheQuick
I am not a big fan of recursion when it is not necessary. Also your code does not work correctly when there is an extension like "archive.tar.gz" but I understand that this is a limitation of GetExtensionPart() and GetFilePart(). For such cases one needs a list of valid extensions because there is no general rule what is an extension and what is not. "tar.gz" is a valid extension but what about "my.book.zip"?
Edit:
More interesting things happen if you got a filename like "Chapter (1234 words).txt" and similar. I know, I know, it's hard to circumvent such issues and most of the time you can simply ignore them but it is important to know that this can happen.
Speaking RegEx: One idea is to really look for a string like "([0-9]+)" and not for "(.+)" . In your case RemoveString() destroys all it finds between the brackets ignoring all trailing characters when the first one is a number.
Re: Adding sequential numbers to a file name
Posted: Thu Jun 21, 2018 2:04 pm
by NicTheQuick
What do you think about this regular expression driven code?
You can also add special file extensions like "tar.gz" if you want to. I already added this as an example.
Also the pattern for numbering is " (number)" including the space at the beginning. So a filename like "test(4)" will not become "test(5)" in the next iteration. Instead it will be "test(5) (2)".
Code: Select all
EnableExplicit
Procedure.s AddSequentialNumber(filename.s)
Static regExFindNumber.i = 0, regExFindExtension.i = 0
If Not regExFindNumber
regExFindNumber = CreateRegularExpression(#PB_Any, " \([1-9][0-9]*\)")
EndIf
If Not regExFindExtension
regExFindExtension = CreateRegularExpression(#PB_Any, "\.[^\.]*$|.tar.gz$") ; Extend at will
EndIf
Protected matchPos.i = 0, matchLength.i = 0, matchNumber.i = 0
If ExamineRegularExpression(regExFindNumber, filename)
While NextRegularExpressionMatch(regExFindNumber)
matchLength = RegularExpressionMatchLength(regExFindNumber)
matchNumber = Val(Mid(RegularExpressionMatchString(regExFindNumber), 3, matchLength - 2))
matchPos = RegularExpressionMatchPosition(regExFindNumber)
Wend
EndIf
Protected result.s
If matchLength
Repeat
matchNumber + 1
result = Left(filename, matchPos + 1) + matchNumber + Mid(filename, matchPos + matchLength - 1)
Until FileSize(result) < 0
Else
matchNumber = 1
If ExamineRegularExpression(regExFindExtension, filename)
If NextRegularExpressionMatch(regExFindExtension)
matchPos = RegularExpressionMatchPosition(regExFindExtension)
matchLength = RegularExpressionMatchLength(regExFindExtension)
Repeat
matchNumber + 1
result = Left(filename, matchPos - 1) + " (" + matchNumber + ")" + Mid(filename, matchPos)
Until FileSize(result) < 0
EndIf
EndIf
If Not matchNumber
Repeat
matchNumber + 1
result = filename + " (" + matchNumber + ")"
Until FileSize(result) < 0
EndIf
EndIf
ProcedureReturn result
EndProcedure
;- Test code below
Define i.i, filename.s = OpenFileRequester("Select a file", "", "", 0)
If filename
For i = 1 To 10
CopyFile(filename, AddSequentialNumber(filename))
Next
EndIf
Re: Adding sequential numbers to a file name
Posted: Fri Jun 29, 2018 10:56 pm
by Dreamland Fantasy
NicTheQuick wrote:I am not a big fan of recursion when it is not necessary. Also your code does not work correctly when there is an extension like "archive.tar.gz" but I understand that this is a limitation of GetExtensionPart() and GetFilePart(). For such cases one needs a list of valid extensions because there is no general rule what is an extension and what is not. "tar.gz" is a valid extension but what about "my.book.zip"?
Edit:
More interesting things happen if you got a filename like "Chapter (1234 words).txt" and similar. I know, I know, it's hard to circumvent such issues and most of the time you can simply ignore them but it is important to know that this can happen.
Speaking RegEx: One idea is to really look for a string like "([0-9]+)" and not for "(.+)" . In your case RemoveString() destroys all it finds between the brackets ignoring all trailing characters when the first one is a number.
Thanks for pointing out those issues. I haven't had a chance to look at them yet, but I will.
Kind regards,
Francis