8

ファイル名から最後の 3 文字をスローして残りを取得したいですか?

私はこのコードを持っています:

char* remove(char* mystr) {

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

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

    return tmp;
}
4

11 に答える 11

18

試す:

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を返すことで、エラー (メモリ不足またはパス) を処理しNULLます。

ファイル以外の部分で/this.path/is_badを見つけるので、のようなものでは機能しませんが、 ofを実行するか、パスセパレーターが何であれ、その位置が位置または位置の前であることを確認することでこれを処理できます。.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]
于 2010-04-29T11:26:59.810 に答える
10

rindexを使用して "." を見つけます。キャラクター。文字列が書き込み可能な場合は、それを文字列ターミネータ文字 ('\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.
于 2010-04-29T11:13:27.533 に答える
6

ファイル名に正確に 3 文字の長さの拡張子があることを何らかの形で知っているため (そしてドットを保持したい場合)、文字通り最後の 3 文字を削除したい場合:

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

ファイル拡張子を一般的に削除したい場合、それは難しく、最終部分だけでなくパスを処理している可能性がある場合は、通常、プラットフォームが提供するファイル名処理ルーチン ( basenamePOSIX では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;
}

考えてみると、ドットで始まるファイル名は単に "." に切り詰めるべきではないため、strrchrdst+1ではなく渡したいと思うかもしれません。dst何のためかによります。

于 2010-04-29T11:23:33.450 に答える
3

次のアルゴリズムを試してみます。

last_dot = -1

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

if last_dot != -1:
    str[last_dot] = '\0'
于 2010-04-29T11:17:25.917 に答える
1

paxdiablo の 2 番目のより汎用的なソリューションを C++ コンパイラで動作させるために、次の行を変更しました。

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

に:

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

これが誰かに役立つことを願っています。

于 2010-06-11T10:29:59.843 に答える
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;
}
于 2015-06-30T20:29:04.037 に答える
0

ドットを「0」に置き換えるだけです。内線番号が常に 3 文字であることがわかっている場合は、次のようにします。

char ファイル[] = "test.png";
ファイル[strlen(ファイル) - 4] = 0;
puts(ファイル);

これにより、「テスト」が出力されます。また、ローカル変数へのポインタを返すべきではありません。コンパイラはこれについても警告します。

于 2010-04-29T11:20:51.600 に答える
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;
}
于 2010-04-29T11:21:14.493 に答える
0

場所を取得し、その場所までを新しい 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);
于 2012-02-16T19:51:14.033 に答える
0

これは拡張子名を変更する簡単な方法です。

....
char outputname[255]
sscanf(inputname,"%[^.]",outputname);  // foo.bar => foo
sprintf(outputname,"%s.txt",outputname) // foo.txt <= foo
....
于 2014-05-29T17:06:37.487 に答える