views:

3983

answers:

8

What's the most efficient way to trim the suffix in Java, like this:

title part1.txt
title part2.html
=>
title part1
title part2
+27  A: 
str.substring(0, str.lastIndexOf('.'))
Svitlana Maksymchuk
Using the overload that takes a `char` is more efficient. That is, str.substring(0, str.lastIndexOf('.'))
erickson
This should be assigned to a new variable as str is not modified.
Nathan Feger
Handle with care: it'll throw an Exception at you if the file name has no suffix.
Andreas_D
+4  A: 
String foo = "title part1.txt";
foo = foo.substring(0, foo.lastIndexOf('.'));
Jherico
Fast, but not fast enough. (+1 for using the char version of indexOf, and for being almost fast enough.)
Michael Myers
No, there might be more than one '.'; you want lastIndexOf('.')
Adam Jaskiewicz
-1 for not using the method I thought you were using. That's now a total of +0 from me. Change it quick! ;)
Michael Myers
+1  A: 

I would do like this:

String title_part = "title part1.txt";
int i;
for(i=title_part.length-1;i>=0 && title_part.charAt(i)!='.';i--);
tittle_part = title_part.substring(0,i);

Starting to the end till the '.' then call substring.

Edit: Might not be a golf but it's effective :)

fmsf
That's basically what lastIndexOf does anyway; why reinvent the wheel?
Michael Myers
For fun and to be a bit descriptive. just that. (and i forgot about lastIndexOf when i was writing this)
fmsf
+1  A: 

Efficient in speed, memory, programmer time, maintainability, ...?

I have found the last two to generally be more important than the first two.

Alex Feinman
A: 
String fileName="foo.bar";
int dotIndex=fileName.lastIndexOf('.');
if(dotIndex>=0) { // to prevent exception if there is no dot
  fileName=fileName.substring(0,dotIndex);
}

Is this a trick question? :p

I can't think of a faster way atm.

Huxi
+8  A: 

This is the sort of code that we shouldn't be doing ourselves. Use libraries for the mundane stuff, save your brain for the hard stuff.

In this case, use FilenameUtils.removeExtension() from Apache Commons IO

skaffman
+3  A: 

As using the String.substring and String.lastIndex in a one-liner is good, there are some issues in terms of being able to cope with certain file paths.

Take for example the following path:

a.b/c

Using the one-liner will result in:

a

That's incorrect.

The result should have been c, but since the file lacked an extension, but the path had a directory with a . in the name, the one-liner method was tricked into giving part of the path as the filename, which is not correct.

Need for checks

Inspired by skaffman's answer, I took a look at the FilenameUtils.removeExtension method of the Apache Commons IO.

In order to recreate its behavior, I wrote a few tests the new method should fulfill, which are the following:

Path                  Filename
--------------        --------
a/b/c                 c
a/b/c.jpg             c
a/b/c.jpg.jpg         c.jpg

a.b/c                 c
a.b/c.jpg             c
a.b/c.jpg.jpg         c.jpg

c                     c
c.jpg                 c
c.jpg.jpg             c.jpg

(And that's all I've checked for -- there probably are other checks that should be in place that I've overlooked.)

The implementation

The following is my implementation for the removeExtension method:

public static String removeExtension(String s) {

    String separator = System.getProperty("file.separator");
    String filename;

    // Remove the path upto the filename.
    int lastSeparatorIndex = s.lastIndexOf(separator);
    if (lastSeparatorIndex == -1) {
        filename = s;
    } else {
        filename = s.substring(lastSeparatorIndex + 1);
    }

    // Remove the extension.
    int extensionIndex = filename.lastIndexOf(".");
    if (extensionIndex == -1)
        return filename;

    return filename.substring(0, extensionIndex);
}

Running this removeExtension method with the above tests yield the results listed above.

The method was tested with the following code. As this was run on Windows, the path separator is a \ which must be escaped with a \ when used as part of a String literal.

System.out.println(removeExtension("a\\b\\c"));
System.out.println(removeExtension("a\\b\\c.jpg"));
System.out.println(removeExtension("a\\b\\c.jpg.jpg"));

System.out.println(removeExtension("a.b\\c"));
System.out.println(removeExtension("a.b\\c.jpg"));
System.out.println(removeExtension("a.b\\c.jpg.jpg"));

System.out.println(removeExtension("c"));
System.out.println(removeExtension("c.jpg"));
System.out.println(removeExtension("c.jpg.jpg"));

The results were:

c
c
c.jpg
c
c
c.jpg
c
c
c.jpg

The results are the desired results outlined in the test the method should fulfill.

coobird
Above and beyond: +1
Tim
A: 

I found coolbird's answer particularly useful.

But I changed the last result statements to:

if (extensionIndex == -1)
  return s;

return s.substring(0, lastSeparatorIndex+1) 
         + filename.substring(0, extensionIndex);

as I wanted the full path name to be returned.

So "C:\Users\mroh004.COM\Documents\Test\Test.xml" becomes 
   "C:\Users\mroh004.COM\Documents\Test\Test" and not
   "Test"
mxro