Gimli[2BV!2B]
29-04-2012, 14:42
Salve a tutti!
Principalmente programmo in C++, quindi ho solitamente a disposizione funzioni adatte per svolgere attività mediamente comuni.
Ora sto facendo qualcosa in C liscio, con poche possibilità di aggiungere dipendenze al progetto: ho quindi la necessità di implementare alcune funzioni di livello piuttosto basso.
Quella di più basso livello con cui mi sono scontrato è una funzione per replace globale all'interno di un array di char (primo dubbio: non esiste proprio un'implementazione standard già disponibile?).
Per non inventare nuovamente la ruota ho cercato un po' in giro, ma non ho trovato implementazioni che mi convincessero al 100% e si adattassero al mio scopo.
Questa è la mia implementazione.
Sono ovviamente dubbioso sulla sua qualità e sicurezza, curioso di imparare dai miei errori.
Consigli? Offese? Derisioni?#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
String replace.
SYNOPSIS
replace_str( &pHaystack, &pHaystack_size, "needle", "replace" )
DESCRIPTION
Sostituisce ricorsivamente una stringa all'interno di un'altra.
-> pHaystack: array di char in elaborazione, passato per riferimento.
Reallocato se necessario.
-> pHaystack_size: massima lunghezza diponibile per haystack (meno il
terminatore di stringa), passato per riferimento. Aggiornato in caso
di reallocazione.
-> needle: stringa che sarà sostituita.
-> replace: stringa che andrà a sostituire needle.
RETURN VALUE
N numero di needle sostituiti
-1 errore, fallita allocazione memoria
*/
int replace_str( char **pHaystack, size_t *pHaystack_size, const char *needle, const char *replace )
{
(*pHaystack)[ *pHaystack_size ] = '\0' ; //precauzione
int nFound = 0 ;
size_t strlen_needle = strlen( needle ) ;
//Prima ricerca per calcolare dimensione finale della stringa
char *current = *pHaystack ;
while( ( current = strstr( current, needle ) ) != NULL )
{
++ nFound ;
current += strlen_needle ;
}
if( nFound == 0 )
return nFound ;
char *buffer = NULL, *str_tmp ;
size_t strlen_with_needle, strlen_post_needle ;
size_t strlen_haystack = strlen( *pHaystack ) ;
size_t strlen_replace = strlen( replace ) ;
size_t strlen_final = strlen_haystack + nFound * ( strlen_replace - strlen_needle ) ;
//Eventuale riallocazione array di char in ingresso se troppo piccolo
if( *pHaystack_size <= strlen_final )
{
if( ( str_tmp = (char*)realloc( *pHaystack, strlen_final + 1 ) ) == NULL )
return -1 ;
(*pHaystack) = str_tmp ;
(*pHaystack_size) = strlen_final ;
}
//Buffer destinato ad ospitare la parte superiore della stringa
//durante la sostituzione
if( ( str_tmp = (char*)malloc( strlen_final + 1 ) ) == NULL )
return -1 ;
buffer = str_tmp ;
//Ricerca ricorrenze per sostituzione
current = *pHaystack ;
while( ( current = strstr( current, needle ) ) != NULL )
{
//Salvataggio porzione successiva ad occorrenza trovata
strlen_with_needle = ( current - *pHaystack ) + strlen_needle ;
strlen_post_needle = strlen_haystack - strlen_with_needle ;
strncpy( buffer, current + strlen_needle, strlen_post_needle + 1 ) ;
//Sostituzione
strncpy( current, replace, strlen_replace ) ;
current += strlen_replace ;
//Ripristino porzione successiva nell'array di origine
strncpy( current, buffer, strlen_post_needle + 1 ) ;
strlen_haystack += ( strlen_replace - strlen_needle ) ;
}
free( buffer ) ;
return nFound ;
}
int main()
{
size_t size = 20 ;
char *test = (char*)malloc( size + 1 ) ;
strcpy( test, "Hello, \\'world\\'!" ) ;
printf( "%s\n", test ) ;
replace_str( &test, &size, "world", "Orlando") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "world", "Orlando") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "'", "''") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\", "\\\\") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\\'", "\"") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "Hello, ", "") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\\"'Orlando\\\"'!", "") ;
printf( "\"%s\"\n", test ) ;
free( test ) ;
size = 5 ;
test = (char*)malloc( size + 1 ) ;
strcpy( test, "00000" ) ;
printf( "%s\n", test ) ;
replace_str( &test, &size, "0", "1") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "1", "22") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "2", "333") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "3", "4444") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "4", "55555") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "5", "666666") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "6", "7777777") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "7", "88888888") ;
printf( "\"%s\"\n", test ) ;
/*
replace_str( &test, &size, "8", "999999999") ;
printf( "\"%s\"\n", test ) ;
*/
free( test ) ;
return 0 ;
}
Principalmente programmo in C++, quindi ho solitamente a disposizione funzioni adatte per svolgere attività mediamente comuni.
Ora sto facendo qualcosa in C liscio, con poche possibilità di aggiungere dipendenze al progetto: ho quindi la necessità di implementare alcune funzioni di livello piuttosto basso.
Quella di più basso livello con cui mi sono scontrato è una funzione per replace globale all'interno di un array di char (primo dubbio: non esiste proprio un'implementazione standard già disponibile?).
Per non inventare nuovamente la ruota ho cercato un po' in giro, ma non ho trovato implementazioni che mi convincessero al 100% e si adattassero al mio scopo.
Questa è la mia implementazione.
Sono ovviamente dubbioso sulla sua qualità e sicurezza, curioso di imparare dai miei errori.
Consigli? Offese? Derisioni?#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
String replace.
SYNOPSIS
replace_str( &pHaystack, &pHaystack_size, "needle", "replace" )
DESCRIPTION
Sostituisce ricorsivamente una stringa all'interno di un'altra.
-> pHaystack: array di char in elaborazione, passato per riferimento.
Reallocato se necessario.
-> pHaystack_size: massima lunghezza diponibile per haystack (meno il
terminatore di stringa), passato per riferimento. Aggiornato in caso
di reallocazione.
-> needle: stringa che sarà sostituita.
-> replace: stringa che andrà a sostituire needle.
RETURN VALUE
N numero di needle sostituiti
-1 errore, fallita allocazione memoria
*/
int replace_str( char **pHaystack, size_t *pHaystack_size, const char *needle, const char *replace )
{
(*pHaystack)[ *pHaystack_size ] = '\0' ; //precauzione
int nFound = 0 ;
size_t strlen_needle = strlen( needle ) ;
//Prima ricerca per calcolare dimensione finale della stringa
char *current = *pHaystack ;
while( ( current = strstr( current, needle ) ) != NULL )
{
++ nFound ;
current += strlen_needle ;
}
if( nFound == 0 )
return nFound ;
char *buffer = NULL, *str_tmp ;
size_t strlen_with_needle, strlen_post_needle ;
size_t strlen_haystack = strlen( *pHaystack ) ;
size_t strlen_replace = strlen( replace ) ;
size_t strlen_final = strlen_haystack + nFound * ( strlen_replace - strlen_needle ) ;
//Eventuale riallocazione array di char in ingresso se troppo piccolo
if( *pHaystack_size <= strlen_final )
{
if( ( str_tmp = (char*)realloc( *pHaystack, strlen_final + 1 ) ) == NULL )
return -1 ;
(*pHaystack) = str_tmp ;
(*pHaystack_size) = strlen_final ;
}
//Buffer destinato ad ospitare la parte superiore della stringa
//durante la sostituzione
if( ( str_tmp = (char*)malloc( strlen_final + 1 ) ) == NULL )
return -1 ;
buffer = str_tmp ;
//Ricerca ricorrenze per sostituzione
current = *pHaystack ;
while( ( current = strstr( current, needle ) ) != NULL )
{
//Salvataggio porzione successiva ad occorrenza trovata
strlen_with_needle = ( current - *pHaystack ) + strlen_needle ;
strlen_post_needle = strlen_haystack - strlen_with_needle ;
strncpy( buffer, current + strlen_needle, strlen_post_needle + 1 ) ;
//Sostituzione
strncpy( current, replace, strlen_replace ) ;
current += strlen_replace ;
//Ripristino porzione successiva nell'array di origine
strncpy( current, buffer, strlen_post_needle + 1 ) ;
strlen_haystack += ( strlen_replace - strlen_needle ) ;
}
free( buffer ) ;
return nFound ;
}
int main()
{
size_t size = 20 ;
char *test = (char*)malloc( size + 1 ) ;
strcpy( test, "Hello, \\'world\\'!" ) ;
printf( "%s\n", test ) ;
replace_str( &test, &size, "world", "Orlando") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "world", "Orlando") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "'", "''") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\", "\\\\") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\\'", "\"") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "Hello, ", "") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "\\\"'Orlando\\\"'!", "") ;
printf( "\"%s\"\n", test ) ;
free( test ) ;
size = 5 ;
test = (char*)malloc( size + 1 ) ;
strcpy( test, "00000" ) ;
printf( "%s\n", test ) ;
replace_str( &test, &size, "0", "1") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "1", "22") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "2", "333") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "3", "4444") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "4", "55555") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "5", "666666") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "6", "7777777") ;
printf( "\"%s\"\n", test ) ;
replace_str( &test, &size, "7", "88888888") ;
printf( "\"%s\"\n", test ) ;
/*
replace_str( &test, &size, "8", "999999999") ;
printf( "\"%s\"\n", test ) ;
*/
free( test ) ;
return 0 ;
}