2010-04-29 12 views
5

Ich möchte die letzten drei Zeichen aus dem Dateinamen und den Rest bekommen?wie man die Erweiterung vom Dateinamen entfernt?

Ich habe diesen Code ein: ""

char* remove(char* mystr) { 

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

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

    return tmp; 
} 
+0

Ist C++ in Ordnung? –

+4

Sie wissen, dass "Dateiendung" und "letzte drei Zeichen eines Dateinamens" ** nicht ** das gleiche sind? Einige Dateien haben mehr oder weniger als 3 Zeichen in ihrem Extenson: 'Foo.java',' foo.c' sind gute Beispiele. Einige haben sogar mehrere Punkte in der Erweiterung (en): 'foo.tar.gz'. Und wieder andere werden einen Punkt außerhalb der Erweiterung haben: 'foo.bar.txt'. Kurz gesagt: Es ist eine nicht-triviale Aufgabe. –

+4

Welche Plattform? Es ist nicht trivial, dies in C korrekt zu tun, und in den Standardbibliotheken ist nichts enthalten (weil Dateinamen plattformspezifisch sind). Zum Beispiel ist ein Backslash ein Pfadtrennzeichen in Windows, aber nicht in * nix, so dass für 'some \ path.to \ file' das Ergebnis des" Entfernens der Erweiterung "unter Windows' some \ path.to \ file' lautet (weil Es gibt keine Erweiterung, aber on * nix ist 'some \ path' (weil die Erweiterung' to \ file' ist). –

Antwort

12

Versuchen:

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

Sie werden zurückgegebenen String selbst befreien müssen. Es findet einfach die letzte . in der Zeichenfolge und ersetzt sie durch ein Nullabschlusszeichen. Es behandelt Fehler (NULL übergeben oder nicht genügend Arbeitsspeicher), indem NULL zurückgibt.

Es wird nicht mit Dingen wie /this.path/is_bad arbeiten, da es die . in der Nicht-Dateiteil zu finden, aber man könnte damit umgehen, indem auch ist, es ist Position ein strrchr von /, oder was auch immer Ihr Pfadseparator ist, und gewährleistet dabei NULL oder vor der . Position.


Eine Allzweck-Lösung könnte für dieses Problem:

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

und dies erzeugt:

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

Ausgezeichnet, gute Arbeit. Vielen Dank. – alaamh

+0

wenn ich nur den Dateinamen ohne Erweiterung und ohne den Pfad möchte? danke – alaamh

+0

Sie haben ein Speicherleck in beiden Fällen, müssen Sie retstr. –

9

Verwenden rindex die lokalisieren Charakter. Wenn die Zeichenfolge beschreibbar ist, können Sie sie durch das Zeichenfolge-Beendigungszeichen ('\ 0') ersetzen, und Sie sind fertig.

Zeichen * 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. 
+3

Damit wird "some/path.name/readme" auf "some/path" abgebildet, was falsch ist. Es könnte sein, dass diese Eingabe unmöglich ist, aber ich denke, es lohnt sich, die Annahmen zu nennen. –

+1

Darüber hinaus können Sie den Funktionsnamen ändern. Die Routine remove() wird im Allgemeinen zum Entfernen/Löschen einer Datei aus dem Verzeichnis verwendet. – Sparky

+4

Es ist erwähnenswert, dass Rindex nicht ISO-C ist: Strrchr kann eine bessere Option sein. – paxdiablo

3

Ich würde versuchen, den folgenden Algorithmus:

last_dot = -1 

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

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

einfach den Punkt ersetzen mit "0". Wenn Sie wissen, dass Ihre Nebenstelle immer 3 Zeichen lang ist, können Sie einfach Folgendes tun:

Dies wird "Test" ausgeben. Außerdem sollten Sie keinen Zeiger auf eine lokale Variable zurückgeben. Der Compiler wird Sie auch davor warnen.

0

Das die Arbeit machen sollte:

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

Wenn Sie buchstäblich nur die letzten drei Zeichen entfernen möchten, weil Sie irgendwie wissen, dass der Dateiname eine Erweiterung genau drei Zeichen lang (und Sie das halten wollen 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; 
} 

Oder der Anrufer bieten den Zielpuffer lassen (was sie sicherstellen müssen, ist lang genug):

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

Wenn Sie eine Dateierweiterung generisch entfernen möchten, ist das schwieriger, und normalerweise sollten Sie die Routinen zur Dateihandhabung Ihrer Plattform verwenden (basename unter POSIX, _wsplitpath_s unter Windows), wenn Sie die Chance haben, eher mit einem Pfad zu arbeiten der letzte Teil des Dateinamens als nur:

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

Kommen Sie, daran zu denken, möchten Sie vielleicht dst+1 passieren, anstatt dst strrchr, da ein Dateiname vielleicht mit einem Punkt beginnen, sollten nicht abgeschnitten werden, um nur " . " Hängt davon ab, wofür es ist.

+0

+1 - Viel besser als meine Antwort. –

1

Um paxdiablo zweit mehr Allzweck-Lösung zu erhalten in einem C++ Compiler zu arbeiten Ich änderte diese Zeile:

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

zu:

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

Hoffnung hilft dieses jemand.

0

Holen Sie sich den Speicherort und kopieren Sie einfach an diesen Ort in ein neues Zeichen *.

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

Dies ist eine einfache Möglichkeit, den Namen einer Nebenstelle zu ändern.

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

Dies gilt für relative Dateipfade, die mit '..' und wahrscheinlich' .' beginnen – bazz

0

Mit konfigurierbarer minimaler Dateilänge und konfigurierbarer maximaler Erweiterungslänge. Gibt den Index zurück, bei dem die Erweiterung in ein Nullzeichen geändert wurde, oder -1, wenn keine Erweiterung gefunden wurde.

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

Ich benutze diesen 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'; 
} 

Es behandelt die Windows-Pfadkonvention richtig (beide / und \ können Pfadtrenn sein).

Verwandte Themen