如何从文件名中删除扩展名?

时间:2010-04-29 11:09:13

标签: c file-extension

我想从文件名中删除最后三个字符并完成剩下的工作吗?

我有这段代码:

char* remove(char* mystr) {

    char tmp[] = {0};
    unsigned int x;

    for (x = 0; x < (strlen(mystr) - 3); x++)
        tmp[x] = mystr[x];

    return tmp;
}

11 个答案:

答案 0 :(得分:15)

尝试:

char *remove(char* mystr) {
    char *retstr;
    char *lastdot;
    if (mystr == NULL)
         return NULL;
    if ((retstr = malloc (strlen (mystr) + 1)) == NULL)
        return NULL;
    strcpy (retstr, mystr);
    lastdot = strrchr (retstr, '.');
    if (lastdot != NULL)
        *lastdot = '\0';
    return retstr;
}

你必须自己释放返回的字符串。它只是找到字符串中的最后一个.,并用空终止符替换它。它将通过返回NULL来处理错误(传递NULL或内存不足)。

它不适用于/this.path/is_bad之类的内容,因为它会在非文件部分找到.,但你可以通过strrchr /来处理这个问题。或者你的路径分隔符是什么,并确保它的位置是NULL或在.位置之前。


针对此问题的更通用的解决方案可能是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// remove_ext: removes the "extension" from a file spec.
//   mystr is the string to process.
//   dot is the extension separator.
//   sep is the path separator (0 means to ignore).
// Returns an allocated string identical to the original but
//   with the extension removed. It must be freed when you're
//   finished with it.
// If you pass in NULL or the new string can't be allocated,
//   it returns NULL.

char *remove_ext (char* mystr, char dot, char sep) {
    char *retstr, *lastdot, *lastsep;

    // Error checks and allocate string.

    if (mystr == NULL)
        return NULL;
    if ((retstr = malloc (strlen (mystr) + 1)) == NULL)
        return NULL;

    // Make a copy and find the relevant characters.

    strcpy (retstr, mystr);
    lastdot = strrchr (retstr, dot);
    lastsep = (sep == 0) ? NULL : strrchr (retstr, sep);

    // If it has an extension separator.

    if (lastdot != NULL) {
        // and it's before the extenstion separator.

        if (lastsep != NULL) {
            if (lastsep < lastdot) {
                // then remove it.

                *lastdot = '\0';
            }
        } else {
            // Has extension separator with no path separator.

            *lastdot = '\0';
        }
    }

    // Return the modified string.

    return retstr;
}

int main (int c, char *v[]) {
    char *s;
    printf ("[%s]\n", (s = remove_ext ("hello", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("hello.", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("hello.txt", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("hello.txt.txt", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("/no.dot/in_path", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("/has.dot/in.path", '.', '/'))); free (s);
    printf ("[%s]\n", (s = remove_ext ("/no.dot/in_path", '.', 0))); free (s);

    return 0;
}

这会产生:

[hello]
[hello]
[hello]
[hello.txt]
[/no.dot/in_path]
[/has.dot/in]
[/no]

答案 1 :(得分:10)

使用 rindex 找到“。”字符。如果该字符串是可写的,您可以用字符串终止符char('\ 0')替换它,然后就完成了。

  

char * rindex(const char * s,int c);

 DESCRIPTION
 The rindex() function locates the last character matching c (converted to a char) in the null-terminated string s.

答案 2 :(得分:6)

如果你真的只想删除最后三个字符,因为你知道你的文件名有一个扩展名正好三个字符长(并且你想保留点):

char *remove_three(const char *filename) {
    size_t len = strlen(filename);
    char *newfilename = malloc(len-2);
    if (!newfilename) /* handle error */;
    memcpy(newfilename, filename, len-3);
    newfilename[len - 3] = 0;
    return newfilename;
}

或者让调用者提供目标缓冲区(他们必须确保足够长):

char *remove_three(char *dst, const char *filename) {
    size_t len = strlen(filename);
    memcpy(dst, filename, len-3);
    dst[len - 3] = 0;
    return dst;
}

如果您想要一般性地删除文件扩展名,那就更难了,并且通常应该使用您的平台提供的任何文件名处理例程(在Windows上为basename,在Windows上为_wsplitpath_s)如果有可能你正在处理一个路径,而不仅仅是文件名的最后部分:

/* warning: may modify filename. To avoid this, take a copy first
   dst may need to be longer than filename, for example currently
   "file.txt" -> "./file.txt". For this reason it would be safer to
   pass in a length with dst, and/or allow dst to be NULL in which
   case return the length required */
void remove_extn(char *dst, char *filename) {
    strcpy(dst, dirname(filename));
    size_t len = strlen(dst);

    dst[len] = '/';
    dst += len+1;

    strcpy(dst, basename(filename));
    char *dot = strrchr(dst, '.');
    /* retain the '.' To remove it do dot[0] = 0 */
    if (dot) dot[1] = 0;
}

考虑一下,您可能希望将dst+1而不是dst传递给strrchr,因为以点开头的文件名可能不应该被截断为“。”。取决于它的用途。

答案 3 :(得分:3)

我会尝试以下算法:

last_dot = -1

for each char in str:
    if char = '.':
        last_dot = index(char)

if last_dot != -1:
    str[last_dot] = '\0'

答案 4 :(得分:1)

为了让paxdiablo的第二个更通用的解决方案在C ++编译器中工作,我更改了这一行:

if ((retstr = malloc (strlen (mystr) + 1)) == NULL)

为:

if ((retstr = static_cast<char*>(malloc (strlen (mystr) + 1))) == NULL)

希望这有助于某人。

答案 5 :(得分:0)

只需将点替换为“0”即可。如果您知道您的分机号码总是3个字符,那么您可以这样做:

char file[] = "test.png";
file[strlen(file) - 4] = 0;
puts(file);

这将输出“test”。此外,您不应该返回指向局部变量的指针。编译器也会警告你。

答案 6 :(得分:0)

这应该做的工作:

char* remove(char* oldstr) {
   int oldlen = 0;
   while(oldstr[oldlen] != NULL){
      ++oldlen;
   }
   int newlen = oldlen - 1;
   while(newlen > 0 && mystr[newlen] != '.'){
      --newlen;
   }
   if (newlen == 0) {
      newlen = oldlen;
   }
   char* newstr = new char[newlen];
   for (int i = 0; i < newlen; ++i){
      newstr[i] = oldstr[i];
   }
   return newstr;
}

答案 7 :(得分:0)

获取位置,然后将该位置复制到新的字符*。

    i = 0;
    n = 0;
    while(argv[1][i] != '\0') { // get length of filename
        i++; }

    for(ii = 0; i > -1; i--) { // look for extension working backwards
        if(argv[1][i] == '.') {
            n = i; // char # of exension
            break; } }

memcpy(new_filename, argv[1], n);

答案 8 :(得分:0)

这是更改扩展名的简单方法。

....
char outputname[255]
sscanf(inputname,"%[^.]",outputname);  // foo.bar => foo
sprintf(outputname,"%s.txt",outputname) // foo.txt <= foo
....

答案 9 :(得分:0)

具有可配置的最小文件长度和可配置的最大扩展长度。返回将扩展名更改为null字符的索引,如果未找到扩展名,则返回-1。

int32_t strip_extension(char *in_str)
{
    static const uint8_t name_min_len = 1;
    static const uint8_t max_ext_len = 4;

    /* Check chars starting at end of string to find last '.' */
    for (ssize_t i = sizeof(in_str); i > (name_min_len + max_ext_len); i--)
    {
        if (in_str[i] == '.')
        {
            in_str[i] = '\0';
            return i;
        }
    }
    return -1;
}

答案 10 :(得分:0)

我使用此代码:

void remove_extension(char* s) {
  char* dot = 0;
  while (*s) {
    if (*s == '.') dot = s;  // last dot
    else if (*s == '/' || *s == '\\') dot = 0;  // ignore dots before path separators
    s++;
  }
  if (dot) *dot = '\0';
}

它正确处理Windows路径约定(/\都可以是路径分隔符。)