2010-04-29 17 views
5

Voglio buttare gli ultimi tre caratteri dal nome del file e ottenere il resto?come rimuovere l'estensione dal nome del file?

ho questo codice: ""

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

C++ è ok? –

+4

Sai che "estensione file" e "ultimi tre caratteri di un nome file" sono ** non ** la stessa cosa? Alcuni file hanno più o meno 3 caratteri nella loro estensione: 'Foo.java',' foo.c' sono buoni esempi. Alcuni hanno anche più punti nelle estensioni: 'foo.tar.gz'. E ancora altri avranno un punto all'esterno dell'estensione: 'foo.bar.txt'. In breve: è un compito non banale. –

+4

Quale piattaforma? Non è banale farlo correttamente in C, e non c'è nulla nelle librerie standard (perché i nomi dei file sono specifici della piattaforma). Ad esempio, una barra rovesciata è un separatore di percorso in Windows ma non in * nix, quindi per 'some \ path.to \ file' il risultato di" rimozione dell'estensione "in Windows è' some \ path.to \ file' (perché non c'è estensione), ma su * nix è 'some \ path' (perché l'estensione è' a \ file'). –

risposta

12

Prova:

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

Dovrete liberare la stringa restituita da soli. Trova semplicemente l'ultimo . nella stringa e lo sostituisce con un carattere di terminazione null. Gestirà gli errori (passando NULL o esaurendo la memoria) restituendo NULL.

Non funzionerà con le cose come /this.path/is_bad dal momento che troverà la . nella parte non-file, ma si poteva gestire questo anche facendo un strrchr di /, o qualunque sia il vostro separatore di percorso è, e garantire la sua posizione è NULL o prima della posizione ..


Una soluzione scopo più generale a questo problema potrebbe essere:

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

e questo produce:

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

Eccellente, ottimo lavoro. Grazie. – alaamh

+0

se voglio solo il nome del file senza estensione e senza il percorso? grazie – alaamh

+0

si ha una perdita di memoria in entrambi i casi, è necessario liberare retstr. –

9

Usa RINDEX per individuare il carattere. Se la stringa è scrivibile, puoi sostituirla con il carattere di terminazione stringa ('\ 0') e il gioco è fatto.

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

Questo mappa "alcuni/path.name/readme" a "alcuni/percorso", che è sbagliato. Potrebbe essere che questo input è impossibile, ma penso che valga la pena di affermare le ipotesi. –

+1

Inoltre, è possibile prendere in considerazione la modifica del nome della funzione. La routine remove() viene generalmente utilizzata per rimuovere/eliminare un file dalla directory. – Sparky

+4

Vale la pena notare che rindex non è ISO-C: strrchr potrebbe essere un'opzione migliore. – paxdiablo

3

vorrei provare il seguente algoritmo:

last_dot = -1 

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

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

basta sostituire il punto con "0". Se sai che la tua estensione è sempre lunga 3 caratteri, puoi semplicemente:

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

Questo emetterà "test". Inoltre, non si dovrebbe restituire un puntatore a una variabile locale. Il compilatore ti avviserà anche di questo.

0

Questo dovrebbe fare il lavoro:

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

Se volete letteralmente solo per rimuovere gli ultimi tre caratteri, perché si sa in qualche modo che il nome del file ha un'estensione esattamente lungo tre caratteri (e si desidera mantenere il 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; 
} 

O lasciare che il chiamante fornisce il buffer di destinazione (che devono garantire è abbastanza lungo):

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

Se si desidera rimuovere genericamente un'estensione di file, è più difficile, e normalmente si dovrebbe usare qualsiasi routine di gestione dei nomi di file fornita dalla piattaforma (basename su POSIX, _wsplitpath_s su Windows) se ci sono possibilità che si tratti di un percorso piuttosto che solo la parte finale del nome del file:

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

Vieni a pensarci bene, si potrebbe desiderare di passare dst+1 piuttosto che dst a strrchr, dal momento che un nome di file che iniziano con un punto forse non dovrebbe essere troncato a solo " . ". Dipende a cosa serve

+0

+1 - Molto meglio della mia risposta. –

1

Per ottenere seconda soluzione scopo più generale di paxdiablo di lavorare in un compilatore C++ Ho modificato questa riga:

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

a:

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

Spero che questo aiuta qualcuno.

0

Ottieni la posizione e copia semplicemente fino a quel punto in un nuovo 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); 
0

Questo è un modo semplice per modificare il nome dell'estensione.

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

Questo è rotto per i percorsi di file relativi che iniziano con '..' e probabilmente' .' – bazz

0

Con lunghezza file configurabile minima e lunghezza massima di estensione configurabile. Restituisce l'indice in cui l'estensione è stata modificata in carattere null o -1 se non è stata trovata alcuna estensione.

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

Io uso questo codice:

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

Gestisce la convenzione percorso di Windows in modo corretto (sia / e \ può essere separatori di percorso).

Problemi correlati