ฉันจะตัดแต่งนามสกุลไฟล์จาก String ใน Java ได้อย่างไร


177

วิธีที่มีประสิทธิภาพมากที่สุดในการตัดส่วนต่อท้ายใน Java เป็นเช่นนี้:

title part1.txt
title part2.html
=>
title part1
title part2

2
รหัสที่มีประสิทธิภาพที่ชาญฉลาดเป็นสิ่งที่คุณหมายถึงฉันหวังว่าไม่ฉลาด CPU
mkoryak

3
เขาไม่ได้ถามว่าจะทำอย่างไรเขาถามว่าอะไรคือวิธีที่มีประสิทธิภาพที่สุด ฉันมาที่นี่เพื่อค้นหาสิ่งเดียวกัน
Edward Falk

คำตอบ:


285

นี่คือรหัสที่เราไม่ควรทำเอง ใช้ห้องสมุดสำหรับสิ่งต่าง ๆ บันทึกสมองของคุณสำหรับสิ่งที่ยาก

ในกรณีนี้ฉันแนะนำให้ใช้FilenameUtils.removeExtension ()จากApache Commons IO


7
ปังอย่างแน่นอน
Joshua Pinter

6
สำหรับ 95% ของโครงการควรเป็นคำตอบที่ยอมรับได้ การเขียนโค้ดซ้ำเช่นนี้เป็นสาเหตุของอาการปวดหัวหลายอย่าง!
Carsten Hoffmann

1
เพียงเพิ่มบรรทัดต่อไปนี้ในการไล่ระดับสีเพื่อเพิ่มการพึ่งพา: - คอมไพล์ 'คอมมอนส์ - ไอโอ: คอมมอนส์ - ไอโอ: 2.6'
Deepak Sharma

ตัวอย่างเช่น
john ktejik

8
หากคุณมี Apache Commons I / O อยู่ในโครงการของคุณอยู่แล้ว แต่ถ้าทั้งหมดนี้คุณต้องการจากนั้นคุณกำลังเพิ่มน้ำหนักอย่างน้อย 2.5 MB ให้กับโครงการของคุณสำหรับสิ่งที่สามารถทำได้อย่างง่ายดายด้วยบรรทัดเดียว
foo

227
str.substring(0, str.lastIndexOf('.'))

8
ควรกำหนดให้กับตัวแปรใหม่เนื่องจาก str ไม่ได้ถูกแก้ไข
นาธาน Feger

51
จัดการด้วยความระมัดระวัง: มันจะส่งข้อยกเว้นให้คุณหากชื่อไฟล์ไม่มีคำต่อท้าย
Andreas Dolk

24
เกี่ยวกับ archive.tar.bz2
อันโตนิโอ

20
if(str.contains(".")) str.substring(0, str.lastIndexOf('.'))
Nicolas Tyler

6
if (str! = null && str.contain (".")) str.substring (0, str.lastIndexOf ('.')) FilenameUtils เป็นอีกการพึ่งพาและไม่สามารถใช้ได้ตลอดเวลา
ocramot

88

เนื่องจากการใช้String.substringและString.lastIndexในหนึ่งซับเป็นสิ่งที่ดีมีปัญหาบางประการในแง่ของความสามารถในการรับมือกับเส้นทางไฟล์บางอย่าง

ใช้ตัวอย่างเส้นทางต่อไปนี้:

a.b/c

การใช้หนึ่งซับจะทำให้:

a

นั่นไม่ถูกต้อง

ผลลัพธ์ควรได้รับcแต่เนื่องจากไฟล์ขาดส่วนขยาย แต่เส้นทางมีไดเรกทอรีที่มี.ชื่อในวิธีหนึ่งซับถูกหลอกให้เป็นส่วนหนึ่งของเส้นทางเป็นชื่อไฟล์ซึ่งไม่ถูกต้อง

ต้องการตรวจสอบ

แรงบันดาลใจจากคำตอบ skaffman ของผมเอาดูที่FilenameUtils.removeExtensionวิธีการของApache Commons IO

เพื่อสร้างพฤติกรรมของมันขึ้นมาใหม่ฉันได้เขียนการทดสอบสองสามครั้งเกี่ยวกับวิธีการใหม่ที่ควรทำซึ่งมีดังต่อไปนี้:

ชื่อไฟล์พา ธ
-------------- --------
A / B / ซีซี
a / b / c.jpg c
a / b / c.jpg.jpg c.jpg

AB / ซีซี
ab / c.jpg c
ab / c.jpg.jpg c.jpg

ซีซี
c.jpg c
c.jpg.jpg c.jpg

(และนั่นคือทั้งหมดที่ฉันได้ตรวจสอบแล้ว - อาจมีเช็คอื่น ๆ ที่ควรอยู่ในตำแหน่งที่ฉันมองข้ามไป)

การดำเนินการ

ต่อไปนี้คือการใช้งานของฉันสำหรับremoveExtensionวิธีการ:

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);
}

การรันremoveExtensionวิธีนี้ด้วยการทดสอบด้านบนจะให้ผลลัพธ์ตามรายการข้างต้น

วิธีการทดสอบด้วยรหัสต่อไปนี้ เนื่องจากสิ่งนี้ถูกเรียกใช้บน Windows ตัวคั่นพา ธ คือสิ่ง\ที่ต้องหลีกด้วย\เมื่อใช้เป็นส่วนหนึ่งของStringตัวอักษร

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"));

ผลการวิจัยพบว่า:

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

ผลลัพธ์คือผลลัพธ์ที่ต้องการซึ่งระบุไว้ในการทดสอบว่าควรทำตามวิธีการใด


4
คำตอบที่ดี มีเหตุผลบางประการที่ทำให้คุณใช้System.getProperty("file.separator")ไม่ใช่แค่File.separator?
halirutan

2
คำเตือน: โซลูชันนี้จะลบพา ธ ก่อนหน้าไม่ใช่เฉพาะส่วนขยายซึ่งแตกต่างจากวิธี Apache Commons IO
59

3
ดูเหมือนว่าสิ่งนี้จะล้มเหลวสำหรับ/path/to/.htaccess
Kuzeko

17

BTW ในกรณีของฉันเมื่อฉันต้องการวิธีแก้ปัญหาอย่างรวดเร็วเพื่อลบส่วนขยายเฉพาะนี่คือสิ่งที่ฉันทำ:

  if (filename.endsWith(ext))
    return filename.substring(0,filename.length() - ext.length());
  else
    return filename;

16
String foo = "title part1.txt";
foo = foo.substring(0, foo.lastIndexOf('.'));

4
ไม่อาจมีมากกว่าหนึ่ง '.'; คุณต้องการ lastIndexOf ('.')
Adam Jaskiewicz

-1 สำหรับการไม่ใช้วิธีที่ฉันคิดว่าคุณกำลังใช้ นั่นคือตอนนี้ทั้งหมด +0 จากฉัน เปลี่ยนอย่างรวดเร็ว! ;)
Michael Myers

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

นี่เป็นคำถามที่หลอกลวงหรือไม่? : p

ฉันไม่สามารถคิดวิธีที่เร็วกว่า atm


7

ใช้วิธีการในcom.google.common.io.Filesชั้นเรียนหากโครงการของคุณขึ้นอยู่กับห้องสมุดหลักของ Google แล้ว getNameWithoutExtensionวิธีการที่คุณต้องมี


ทำไมบางคนไม่เห็นด้วยกับคำตอบของฉัน
Toby

โปรดทราบว่าผลตอบแทนนี้ชื่อฐานเท่านั้นดังนั้นเส้นทางยังเป็นลบ: google.github.io/guava/releases/19.0/api/docs/com/google/common/...
thSoft

6

คุณสามารถลองใช้ฟังก์ชันนี้พื้นฐานได้

public String getWithoutExtension(String fileFullPath){
    return fileFullPath.substring(0, fileFullPath.lastIndexOf('.'));
}

5

ฉันพบว่าคำตอบของ coolbirdมีประโยชน์เป็นพิเศษ

แต่ฉันเปลี่ยนงบผลลัพธ์ล่าสุดเป็น:

if (extensionIndex == -1)
  return s;

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

ตามที่ฉันต้องการให้ชื่อพา ธ เต็มจะถูกส่งกลับ

ดังนั้น "C: \ Users \ mroh004.COM \ Documents \ Test \ Test.xml" จึงกลายเป็น 
   "C: \ Users \ mroh004.COM \ Documents \ Test \ Test" และไม่ใช่
   "ทดสอบ"

5
filename.substring(filename.lastIndexOf('.'), filename.length()).toLowerCase();

3
ตรงข้ามกับสิ่งที่ถูกถามและไม่จำเป็นต้องผ่านความยาวเพียงแค่ใช้หนึ่งสตริงย่อย arg

4

ใช้ regex อันนี้แทนที่จุดสุดท้ายและทุกอย่างที่อยู่หลังมัน

String baseName = fileName.replaceAll("\\.[^.]*$", "");

คุณยังสามารถสร้างวัตถุรูปแบบได้หากคุณต้องการคอมไพล์ regex ล่วงหน้า


1
String[] splitted = fileName.split(".");
String fileNameWithoutExtension = fileName.replace("." + splitted[splitted.length - 1], "");

ต้องแยก"\\."เป็น "." เป็นพิเศษสำหรับ regex
Compass

1

สร้างไฟล์ใหม่ด้วยเส้นทางภาพสตริง

String imagePath;
File test = new File(imagePath);
test.getName();
test.getPath();
getExtension(test.getName());


public static String getExtension(String uri) {
        if (uri == null) {
            return null;
        }

        int dot = uri.lastIndexOf(".");
        if (dot >= 0) {
            return uri.substring(dot);
        } else {
            // No extension.
            return "";
        }
    }

1

org.apache.commons.io.FilenameUtils เวอร์ชัน 2.4 ให้คำตอบต่อไปนี้

public static String removeExtension(String filename) {
    if (filename == null) {
        return null;
    }
    int index = indexOfExtension(filename);
    if (index == -1) {
        return filename;
    } else {
        return filename.substring(0, index);
    }
}

public static int indexOfExtension(String filename) {
    if (filename == null) {
        return -1;
    }
    int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
    int lastSeparator = indexOfLastSeparator(filename);
    return lastSeparator > extensionPos ? -1 : extensionPos;
}

public static int indexOfLastSeparator(String filename) {
    if (filename == null) {
        return -1;
    }
    int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
    int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
    return Math.max(lastUnixPos, lastWindowsPos);
}

public static final char EXTENSION_SEPARATOR = '.';
private static final char UNIX_SEPARATOR = '/';
private static final char WINDOWS_SEPARATOR = '\\';


0

ฉันจะทำสิ่งนี้:

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

เริ่มต้นจนจบจนถึง '.' จากนั้นเรียกสตริงย่อย

แก้ไข: อาจไม่ใช่กอล์ฟ แต่มีผล :)


7
นั่นเป็นสิ่งที่ lastIndexOf ทำอยู่ดี ทำไมต้องบูรณาการล้อ
Michael Myers

เพื่อความสนุกสนานและเป็นคำอธิบายเล็กน้อย แค่นั้น. (และฉันลืมเกี่ยวกับ lastIndexOf เมื่อผมเขียนนี้)
FMSF

0

โปรดคำนึงถึงสถานการณ์ที่ไม่มีนามสกุลไฟล์หรือมีนามสกุลไฟล์มากกว่าหนึ่ง

ตัวอย่างชื่อไฟล์: ไฟล์ | file.txt | file.tar.bz2

/**
 *
 * @param fileName
 * @return file extension
 * example file.fastq.gz => fastq.gz
 */
private String extractFileExtension(String fileName) {
    String type = "undefined";
    if (FilenameUtils.indexOfExtension(fileName) != -1) {
        String fileBaseName = FilenameUtils.getBaseName(fileName);
        int indexOfExtension = -1;
        while (fileBaseName.contains(".")) {
            indexOfExtension = FilenameUtils.indexOfExtension(fileBaseName);
            fileBaseName = FilenameUtils.getBaseName(fileBaseName);
        }
        type = fileName.substring(indexOfExtension + 1, fileName.length());
    }
    return type;
}

0
String img = "example.jpg";
// String imgLink = "http://www.example.com/example.jpg";
URI uri = null;

try {
    uri = new URI(img);
    String[] segments = uri.getPath().split("/");
    System.out.println(segments[segments.length-1].split("\\.")[0]);
} catch (Exception e) {
    e.printStackTrace();
}

นี่จะเป็นตัวอย่างเอาต์พุตสำหรับทั้งimgและimgLink


0
public static String removeExtension(String file) {
    if(file != null && file.length() > 0) {
        while(file.contains(".")) {
            file = file.substring(0, file.lastIndexOf('.'));
        }
    }
    return file;
}

สิ่งนี้จะเปลี่ยน "a.jpg.jpg" เป็น "a" แทน (ถูกต้อง) "a.jpg" จุดประสงค์อะไรที่ให้บริการfile.length() > 0เช็ค?
Klaus Gütter

คำถามหลักคือ "เอาส่วนขยายออกได้อย่างไร" ดังนั้นใช่การเปลี่ยน "a.txt.zip" เป็น "a" และ ".htaccess" เป็นความว่างเปล่า ฟังก์ชั่นนี้ใช้งานได้กับ Strings ดังนั้นชื่อไฟล์ต้องไม่เป็นโมฆะ แต่ยังคงมีความยาวได้ 0 ตรวจสอบได้เร็วขึ้นว่าคุ้มค่าก่อนแยกวิเคราะห์สัญลักษณ์หรือไม่ ความนับถือ.
Alexey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.