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

发布于 2024-08-30 08:35:59 字数 239 浏览 4 评论 0原文

我想抛出文件名中的最后三个字符并获取其余字符?

我有这个代码:

char* remove(char* mystr) {

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

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

    return tmp;
}

I want to throw the last three character from file name and get the rest?

I have this code:

char* remove(char* mystr) {

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

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

    return tmp;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

旧人九事 2024-09-06 08:35:59

尝试:

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

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

它不适用于 /this.path/is_bad 之类的东西,因为它会在非文件部分找到 . 但您也可以通过执行 < / 的 code>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.
//   extSep is the extension separator.
//   pathSep 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 extSep, char pathSep) {
    char *retStr, *lastExt, *lastPath;

    // 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);
    lastExt = strrchr (retStr, extSep);
    lastPath = (pathSep == 0) ? NULL : strrchr (retStr, pathSep);

    // If it has an extension separator.

    if (lastExt != NULL) {
        // and it's to the right of the path separator.

        if (lastPath != NULL) {
            if (lastPath < lastExt) {
                // then remove it.

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

            *lastExt = '\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]

Try:

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

You'll have to free the returned string yourself. It simply finds the last . in the string and replaces it with a null terminator character. It will handle errors (passing NULL or running out of memory) by returning NULL.

It won't work with things like /this.path/is_bad since it will find the . in the non-file portion but you could handle this by also doing a strrchr of /, or whatever your path separator is, and ensuring it's position is NULL or before the . position.


A more general purpose solution to this problem could be:

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

// remove_ext: removes the "extension" from a file spec.
//   myStr is the string to process.
//   extSep is the extension separator.
//   pathSep 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 extSep, char pathSep) {
    char *retStr, *lastExt, *lastPath;

    // 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);
    lastExt = strrchr (retStr, extSep);
    lastPath = (pathSep == 0) ? NULL : strrchr (retStr, pathSep);

    // If it has an extension separator.

    if (lastExt != NULL) {
        // and it's to the right of the path separator.

        if (lastPath != NULL) {
            if (lastPath < lastExt) {
                // then remove it.

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

            *lastExt = '\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;
}

and this produces:

[hello]
[hello]
[hello]
[hello.txt]
[/no.dot/in_path]
[/has.dot/in]
[/no]
妥活 2024-09-06 08:35:59

使用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.

注意:更高版本的 gcc 以及其他编译器可能无法识别这一点。相反,应使用 #include string.h 代替 strings.h,并使用 strrchr

Use rindex to locate the "." character. If the string is writable, you can replace it with the string terminator char ('\0') and you're done.

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.

NOTE: This will not be recognized by later versions of gcc, and, probably, other compilers. Instead, #include string.h instead of strings.h, and use strrchr.

寂寞陪衬 2024-09-06 08:35:59

如果您实际上只想删除最后三个字符,因为您以某种方式知道您的文件名的扩展名正好是三个字符长(并且您想保留点):

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

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

/* 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,因为以点开头的文件名可能不应该被截断为仅“.”。取决于它的用途。

If you literally just want to remove the last three characters, because you somehow know that your filename has an extension exactly three chars long (and you want to keep the dot):

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

Or let the caller provide the destination buffer (which they must ensure is long enough):

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

If you want to generically remove a file extension, that's harder, and should normally use whatever filename-handling routines your platform provides (basename on POSIX, _wsplitpath_s on Windows) if there's any chance that you're dealing with a path rather than just the final part of the filename:

/* 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;
}

Come to think of it, you might want to pass dst+1 rather than dst to strrchr, since a filename starting with a dot maybe shouldn't be truncated to just ".". Depends what it's for.

青芜 2024-09-06 08:35:59

我会尝试以下算法:

last_dot = -1

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

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

I would try the following algorithm:

last_dot = -1

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

if last_dot != -1:
    str[last_dot] = '\0'
反目相谮 2024-09-06 08:35:59

只需将点替换为“0”即可。如果你知道你的扩展名总是 3 个字符长,你可以这样做:

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

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

Just replace the dot with "0". If you know that your extension is always 3 characters long you can just do:

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

This will output "test". Also, you shouldn't return a pointer to a local variable. The compiler will also warn you about this.

贵在坚持 2024-09-06 08:35:59

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

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

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

:希望这对某人有帮助。

To get paxdiablo's second more general purpose solution to work in a C++ compiler I changed this line:

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

to:

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

Hope this helps someone.

缱倦旧时光 2024-09-06 08:35:59

这应该可以完成这项工作:

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

This should do the job:

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;
}
杀お生予夺 2024-09-06 08:35:59

获取位置并将该位置复制到新的 char * 中。

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

Get location and just copy up to that location into a new char *.

    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);
时光与爱终年不遇 2024-09-06 08:35:59

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

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

This is simple way to change extension name.

....
char outputname[255]
sscanf(inputname,"%[^.]",outputname);  // foo.bar => foo
sprintf(outputname,"%s.txt",outputname) // foo.txt <= foo
....
∝单色的世界 2024-09-06 08:35:59

具有可配置的最小文件长度和可配置的最大扩展长度。返回扩展名更改为空字符的索引,如果未找到扩展名,则返回 -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;
}

With configurable minimum file length and configurable maximum extension length. Returns index where extension was changed to null character, or -1 if no extension was found.

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;
}
空城旧梦 2024-09-06 08:35:59

我使用这段代码:

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 路径约定(/\ 都可以是路径分隔符)。

I use this code:

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

It handles the Windows path convention correctly (both / and \ can be path separators).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文