Adding sequential numbers to a file name

Share your advanced PureBasic knowledge/code with the community.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Adding sequential numbers to a file name

Post 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
Last edited by Dreamland Fantasy on Sat Jun 02, 2018 4:56 pm, edited 1 time in total.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Adding sequential numbers to a file name

Post by Dude »

Works well. I tried to break it and make it destroy a bunch of existing files, and it didn't. Good job! :mrgreen:
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Adding sequential numbers to a file name

Post 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! :mrgreen:
Thanks for testing it out. :D

Kind regards,

Francis
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Re: Adding sequential numbers to a file name

Post 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
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Adding sequential numbers to a file name

Post 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
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Adding sequential numbers to a file name

Post by davido »

@Dreamland Fantasy,
Works well, thank you for sharing.
DE AA EB
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Adding sequential numbers to a file name

Post by Dreamland Fantasy »

Thanks for trying it out davido. :)

Kind regards,

Francis
User avatar
NicTheQuick
Addict
Addict
Posts: 1224
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Adding sequential numbers to a file name

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
NicTheQuick
Addict
Addict
Posts: 1224
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Adding sequential numbers to a file name

Post 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
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Adding sequential numbers to a file name

Post 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
Post Reply