Newbie ??: deleting single character in filename

Hello-
I’m working on a simple script that should allow the user to choose a folder with several files, check each filename (ex: 147345b.jpg) and, if a “b” is in the filename (typically character -5 - right before the “.jpg”) remove the “b” from the filename. You can see, from what I have so far, that I’m not quite there:

tell application "Finder"
	try
		set kFiles to every file of (choose folder)
		repeat with currFile in kFiles
			if (character -5 of currFile) is "b" then
				set temp_filename to name of currFile
				set new_name to ((characters -6 through 1 of temp_filename) & ".jpg")
				set name of currFile to new_name
			end if
		end repeat
	end try
end tell

Any help is greatly appreciated!!!

karmaChrome,

After the line:

repeat with currFile in kFiles

You need to set another variable to the name of the file “currFile” in order to make the text check that follows.

repeat with currFile in kFiles
	set thisName to name of currFile
	if (character -5 of thisName) is "b" then
		set temp_filename to thisName
		set new_name to ((characters -6 through 1 of temp_filename) & ".jpg")
		set name of currFile to new_name
	end if
end repeat

PreTech

Edit: I didn’t see PreTech’s post before I made mine, but he is correct. You’ll need to make that change as well.

I think you just need to change this line.

set new_name to ((characters -6 through 1 of temp_filename) & ".jpg")

. to this:

set new_name to ((text 1 through -6 of temp_filename) & ".jpg")

You could also do it like this:

tell application "Finder"
	activate
	
	-- You should always "save" the current delimiters so they can be set back afterwards.
	set ASTID to AppleScript's text item delimiters
	
	try
		choose folder with prompt "Replace b's in every file of this folder:"
		set allFiles to files of result
		
		repeat with thisFile in allFiles
			set thisName to name of thisFile
			
			-- Don't want to change the extension, so take it off the name, but save it for later.
			set AppleScript's text item delimiters to {"."}
			try
				-- This tries to get the name w/o the extension. (I'll expand on this line later.)
				set newName to text 1 thru text item -2 of thisName
				
				-- Get the extension so we can put it "back on" later.
				set thisExtension to "." & (text item -1 of thisName)
			on error
				-- This filename has no extension.
				set newName to thisName
				set thisExtension to ""
			end try
			
			-- Break apart newName at every "b", and get the resulting items.
			set AppleScript's text item delimiters to {"b"}
			set newName to text items of newName
			
			-- Put the items back together. The current delimiter is inserted between the items when this happens.
			set AppleScript's text item delimiters to {""}
			set newName to (newName as Unicode text) & thisExtension
			
			-- The b's have been removed, and the extension (if any) has been added. Now, tell Finder to change the name.
			set name of thisFile to newName
		end repeat
	end try
	
	-- Restore the original delimiters. In this case, it's done after the try block, so they will be changed back even if an error occurs.
	set AppleScript's text item delimiters to ASTID
end tell

This will replace any b’s in the filenames (but not extensions).

Wonderful - thanks. I thought I was close…though I would have never thought to use delimiters.

This isn’t as fast as the ASTID method, but the strip handler may be useful to someone:

tell application "Finder"
	try
		set fileList to every file of (choose folder)
		repeat with f in fileList
			set fileName to name of f
			set fileNameAdjusted to my StripStringExpression(fileName, "b")
			set name of fileName to fileNameAdjusted
		end repeat
	end try
end tell

on StripStringExpression(theString, theExpression)
	return (do shell script "/bin/echo" & space & quoted form of theString & space & "| /usr/bin/sed -e 's/" & theExpression & "//g'")
end StripStringtheExpression

In theory, you could pass a regex to the strip handler, as well.

Mikey, your script affects the extension as well.

'Scuse me Bruce - if you have a few minutes to spare, could you please comment on some of the segments of your script? I’m fascinated by how you used delimeters here and I’ve little experience with them yet. thanks.

No problem, karmaChrome. I’ve added some comments to my original script. Please let me know if I should be more verbose about any of it.

Now, about this line.

set newName to text 1 thru text item -2 of thisName

.as compared to this one:

set newName to (text items 1 thru -2 of thisName) as text

Both of those lines break up a string using delimiters, get the desired items, and then back together (with the delimiter character inserted in between). However, the first script is faster.

I wish I could explain the reason better, but I only realized this recently. (Thanks kai.[1]) Basically, the second script has to make a list, but the first one doesn’t.

[1] Strip Extension. Tricky

Ack, yeah, I was in a rush to head out somewhere and that skipped my mind. Corrected:

tell application "Finder"
	try
		set fileList to every file of (choose folder)
		repeat with f in fileList
			set fileName to name of f
			set fileNameAdjusted to (my GetBasenameSansExtension(my StripStringExpression(fileName, "b")) & my GetFileExtension(fileName))
			set name of fileName to fileNameAdjusted
		end repeat
	end try
end tell

on GetBasenameSansExtension(POSIXObject)
	return (do shell script "/usr/bin/basename" & space & quoted form of POSIXObject & space & "| /usr/bin/sed -e 's/\\.[^.]*$//'")
end GetBasenameSansExtension

on GetFileExtension(theString)
	return (do shell script "echo=/bin/echo ; file=`$echo" & space & quoted form of theString & "` ; ext=${file##*.} ; $echo \".$ext\"")
end GetFileExtension

on StripStringExpression(theString, theExpression)
	return (do shell script "/bin/echo" & space & quoted form of theString & space & "| /usr/bin/sed -e 's/" & theExpression & "//g'")
end StripStringExpression

So yeah, pretty much just a few portable functions people might find useful and a way to show them in context of use. Flexible, but at a small speed sacrifice. (They could be grouped into a single shell script for a big speed increase, but this was written for flexibility, not speed.)

You can feed GetBasenameSansExtension() a full path, part of a path, or just a file name.

Yeah - for a while now, I’ve been thinking that it might be helpful if we tried to clarify this issue a little, Bruce.

The second method certainly does ‘break up the string’ at certain points (wherever the current value of AppleScript’s text item delimiters appears in it) to produce a list. Then, because of the “as text” statement, it coerces that list back to a string (inserting the current value of AppleScript’s text item delimiters between each listed item).

The first method, though, is rather more direct. The best way I can describe the process is that it uses text elements* as positional markers, to denote where the required text should start and end - and simply extracts the text between (and including) those points (without coercion, conversion or any other kind of manipulation).

* Examples of a text element include:

The statement:

set newName to text 1 thru text item -2 of thisName

… is actually a shorter way of saying:

set newName to text from character 1 to text item -2 of thisName

(While the first form may be more convenient to use, the second probably demonstrates the principle of positional marking slightly more clearly.)

Confusion over the use of these methods is perhaps more common when dealing with characters. However, the topic Substring: “text” against “characters” may now help - by explaining the general differences in a little more detail…
:slight_smile: