The effective way to Get File Name without Extension.

Here are two alternatives

set aFile to (choose file)
set {name:Nm, name extension:Ex} to (info for aFile) -- info for is deprecated for ages but is still working
set baseName to text 1 thru ((get offset of "." & Ex in Nm) - 1) of Nm

set posixPath to POSIX path of (choose file)
set baseName to (current application's NSURL's fileURLWithPath:posixPath)'s URLByDeletingPathExtension()'s lastPathComponent() as text

Your 1st script takes about 470.0 microseconds, the 2nd about 27.0 microseconds. Without choosing file code line, as mine. I tried it few times.

First things first: your code fails if the base name also contains a “.”.

Ops, how to fix that better? Ideas?

This, as I see, solves that problem.


set posixPath to POSIX path of (choose file)

set TID to text item delimiters
set text item delimiters to {"/"}
set baseName to last text item of posixPath
set text item delimiters to {"."}
try
	set nameWithoutExtension to (text items 1 thru -2 of baseName) as string
on error
	set nameWithoutExtension to baseName
end try
set text item delimiters to TID

nameWithoutExtension

Now it takes about 2.5 microseconds.

Howz about:


set posixPath to POSIX path of (choose file)

set TID to text item delimiters
set text item delimiters to {"/"}
if (posixPath ends with "/") then
	set baseName to text item -2 of posixPath
else
	set baseName to last text item of posixPath
end if
if (baseName contains ".") then
	set text item delimiters to {"."}
	set nameWithoutExtension to text 1 thru text item -2 of baseName
else
	set nameWithoutExtension to baseName
end if
set text item delimiters to TID

nameWithoutExtension

Thanks, Nigel. Your script takes about 1.85 microseconds, so your solution for “.” problem is preferable from mine. I can’t still understand why it is faster. :slight_smile: It is using text instead of as string, I think. Or, removing the try block ?.

Oh, I understand. No need try block, because if not dots in base name, base name has not extension!

And, you added if (posixPath ends with “/”) then for bundles and packages! Yes, your script goes as the best to my Scripts library.

I didn’t actually time it. :slight_smile: The main aim was make your own script slightly more reliable. But text 1 thru text item -2 of basename is slightly more efficient than (text items 1 thru -2 of baseName) as string because it extracts the substring directly instead of creating and coercing an intermediate list. In the case of try vs. if, it seems to be a matter of overall balance. When there is an extension, the if statement adds a test into the process, but this has apparently been offset by using text 1 thru text item -2… instead of (text items 1 thru -2…. When there isn’t an extension, the time taken to do the test and nothing else is likely to be very much less than the time taken to reset the TIDs, attempt the text extraction, and recover from the error.

Stefan’s suggestion above can be done entirely with NSString methods. It might be interesting to see how these compare with the NSURL ones:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set posixPath to POSIX path of (choose file)
set baseName to (current application's NSString's stringWithString:posixPath)'s stringByDeletingPathExtension()'s lastPathComponent() as text
-- Or (with a shorter intermediate string):
set baseName to (current application's NSString's stringWithString:posixPath)'s lastPathComponent()'s stringByDeletingPathExtension() as text

About 48.0 microseconds on my machine.

Did you remember to comment out one of the set baseName … lines before testing? The timings should be pretty the same as for Stefan’s ASObjC script.

No, I forget. :slight_smile: I will test again now.

OK, I tested again. The first code line takes about 27 microseconds, the second - about 25 microseconds. It seems, 3 ASObjC methods uses the same algorithm :).

Here’s a slight modification of Nigel’s script that retains the period character in the nameWithoutExtension return value for base names that end with a period character, in which case the period character does not serve as a file extension delimiter. The only change is the addition of the phrase and (baseName does not end with “.”)


set posixPath to POSIX path of (choose file)

set TID to text item delimiters
set text item delimiters to {"/"}
if (posixPath ends with "/") then
	set baseName to text item -2 of posixPath
else
	set baseName to last text item of posixPath
end if
if (baseName contains ".") and (baseName does not end with ".") then
	set text item delimiters to {"."}
	set nameWithoutExtension to text 1 thru text item -2 of baseName
else
	set nameWithoutExtension to baseName
end if
set text item delimiters to TID

nameWithoutExtension

Hi bmose.

There may not be much point to your modification. Both versions work in all cases. Yours saves having to set and use the TIDs when the name ends with “.”, but adds an extra check which is carried out with every name containing that character.

Hi Nigel,

When I apply the code to the sample POSIX path “/qwer/asdf/zxcv.”, the original version returns “zxcv” for nameWithoutExtension, whereas the proposed modified version returns “zxcv.”, which I believe is the correct name without extension. Am I missing something?

Maybe I am. I’d consider a trailing “.” to be either the extension or the separator between the rest of the name and an implied “” extension. However, applying NSString or NSURL methods to the task returns your result:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"

set aPath to current application's class "NSString"'s stringWithString:("/qwer/asdf/zxcv.")
set nameWithoutExtension to (aPath's lastPathComponent()'s stringByDeletingPathExtension()) as text
-- "zxcv."

But then again, they return “” for the extension itself. In all other cases, both the extension and the dot are removed, so it’s inconsistent.

I understand your point. One case where the period would be part of the name rather than the extension would be the hidden files “.” and “…”, no? But outside of that peculiar case, I suppose that because it’s not customary to name files with a trailing period, there is some ambiguity in its interpretation.

I created a test file with the following name.

Test File 12.12.19

This file has no extension and the 19 at the end of the file name is the current year.

Every script in this thread (except for two that wouldn’t work for me) returned a file name without extension as:

Test File 12.12

Even a Finder window shows the file name with extension hidden as:

Test File 12.12

I ran the following script on the test file:

tell application "Finder"
	set thefile to selection as alias
	set fileName to name of thefile
	set fileExtension to name extension of thefile
	if fileExtension > "" then
		set fileNameWithoutExtension to text 1 thru -((count fileExtension) + 2) of fileName
	else
		set fileNameWithoutExtension to fileName
	end if
end tell

fileNameWithoutExtension

This script recognizes that 19 is part of the file name and not an extension and correctly returns fileNameWithoutExtension as:

Test File 12.12.19

How does this script identify 19 as part of the file name and not an extension–or is something else going on?

Thanks.

Others may correct me if I’m wrong, but I don’t think it’s possible to name a file with a period (i.e., character id 46) following by non-period characters. The portion of the name beginning with the final period will always be interpreted as a file extension. In the above case, .19 would always be interpreted as being a file extension. I don’t know of any way to get around this restriction other than perhaps to replace the period characters with middle dot characters (character id 183), hyphens, or something similar in the file name:

12·12·19
-or-
12-12-19

Thanks bmose. What you say makes absolute sense to me. In fact, I ran “info for” on my test file and it showed the file extension to be “19”. What confused me was that my script when run on the test file returns “” (i.e. an empty string) for the fileExtension variable. I think I’m making some rookie mistake in my script but I can’t figure it out.

I don’t think so. You see a similar thing if you just select the item in the Finder and hit return: with your name, the whole name is selected, rather than all up to the last dot.

I’m guessing the Finder only regards an extension as valid if the system or some app has claimed it and the file therefore has a non-dynamic UTI. But that definition flies in the face of everything else.

It seems to me yet another to the list of reasons not to use Finder scripting where possible.