Biorąc pod uwagę ( char *) ciąg, chcę znaleźć wszystkie wystąpienia podciągu i zastąpić je alternatywnym ciągiem. Nie widzę żadnej prostej funkcji, która to zapewnia <string.h>.
Optymalizator powinien wyeliminować większość zmiennych lokalnych. Wskaźnik tmp jest po to, aby upewnić się, że strcpy nie musi przechodzić przez łańcuch, aby znaleźć wartość null. tmp wskazuje koniec wyniku po każdym wywołaniu. (Zobacz algorytm malarza Shlemiela, aby dowiedzieć się, dlaczego strcpy może być denerwujący).
// You must free the result if result is non-NULL.char *str_replace(char *orig, char *rep, char *with){
char *result; // the return stringchar *ins; // the next insert pointchar *tmp; // variesint len_rep; // length of rep (the string to remove)int len_with; // length of with (the string to replace rep with)int len_front; // distance between rep and end of last repint count; // number of replacements// sanity checks and initializationif (!orig || !rep)
returnNULL;
len_rep = strlen(rep);
if (len_rep == 0)
returnNULL; // empty rep causes infinite loop during countif (!with)
with = "";
len_with = strlen(with);
// count the number of replacements needed
ins = orig;
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
if (!result)
returnNULL;
// first time through the loop, all the variable are set correctly// from here on,// tmp points to the end of the result string// ins points to the next occurrence of rep in orig// orig points to the remainder of orig after "end of rep"while (count--) {
ins = strstr(orig, rep);
len_front = ins - orig;
tmp = strncpy(tmp, orig, len_front) + len_front;
tmp = strcpy(tmp, with) + len_with;
orig += len_front + len_rep; // move to next "end of rep"
}
strcpy(tmp, orig);
return result;
}
@jmucchiello: użyj size_tzamiast intdla dowolnych rozmiarów obiektów / ciągów i indeksów do nich. Jaki jest cel strcpy(tmp, orig);na samym końcu? Wydaje się źle.
Alexey Frunze
@Alex, ostatni strcpy (tmp, orig) kopiuje ostatnią część ciągu do miejsca docelowego. Na przykład: replace („abab”, „a”, „c”) na końcu pętli, wynik zawiera, „cbc”, a początek wskazuje ostatnie „b” w „abab”. Ostatni strcpy dołącza „b”, więc zwrócony ciąg to „cbcb”. Jeśli nie ma już nic do skopiowania, orig powinien wskazywać na ASCIIZ ciągu wejściowego.
jmucchiello
uproszczenie: pierwszą forpętlę można zamienić na for (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}, a następnie tmpsłuży ona tylko do pisania.
Ostrzegamy, że ta funkcja zwraca NULL, jeśli nie ma żadnych wystąpień do zamiany (if (! (Ins = strstr (orig, rep))) return NULL;). Nie możesz po prostu użyć wyjścia, musisz sprawdzić, czy wyjście ma wartość NULL, a jeśli tak, użyj oryginalnego ciągu (nie kopiuj po prostu wskaźnika do ciągu wynikowego, ponieważ free (wynik) zwalnia oryginalny ciąg). Użycie jest prostsze, jeśli ciąg wejściowy jest po prostu kopiowany do ciągu wyjściowego, jeśli nie ma nic do zastąpienia.
Adversus
18
Nie jest to zapewnione w standardowej bibliotece C, ponieważ podając tylko znak * nie można zwiększyć pamięci przydzielonej do ciągu, jeśli zastępujący ciąg jest dłuższy niż zastępowany ciąg.
Możesz to zrobić łatwiej, używając std :: string, ale nawet tam żadna funkcja nie zrobi tego za Ciebie.
1 / strlen (char *) + 1 niekoniecznie jest równe rozmiarowi pamięci. 2 / Istnieje wiele wersji N funkcji łańcuchowych, które otrzymują i dodatkowy parametr rozmiaru bufora, więc nie ma powodu, dla którego nie może istnieć funkcja snreplace (). 3 / mogłaby istnieć funkcja zastępowania w miejscu, a nie zastępowania w miejscu. 4 / Jak myślisz, jak działa Sprintf? Ma on argument char * i nie musi zwiększać alokacji pamięci, więc nie ma powodu, dla którego zamiana też nie mogłaby zadziałać ... (chociaż C ma zły projekt "string" i rozmiar bufora zawsze powinien być przekazywany ze wskaźnikiem => snprintf)
Steven Spark
12
Nie ma takiego.
Musiałbyś stworzyć własny, używając czegoś takiego jak strstr i strcat lub strcpy.
Gdzie są przechowywane kolekcje fanów często używanych funkcji? Na pewno jest już do tego biblioteka…
Pacerier,
1
strcat()to zła sugestia.
Iharob Al Asimi
11
Możesz zbudować własną funkcję zamiany, używając strstr, aby znaleźć podciągi i strncpy do skopiowania części do nowego bufora.
O ile to, co chcesz, replace_withma taką samą długość, jak chcesz replace, to prawdopodobnie najlepiej jest użyć nowego bufora do skopiowania nowego ciągu.
Ponieważ łańcuchy w C nie mogą dynamicznie rosnąć, podstawianie w miejscu generalnie nie będzie działać. Dlatego musisz przydzielić miejsce na nowy ciąg, który ma wystarczająco dużo miejsca na twoje podstawienie, a następnie skopiować części z oryginału wraz z podstawieniem do nowego ciągu. Aby skopiować części, użyłbyś strncpy .
Rozmiar bufora może być większy niż strlen, ciąg zastępujący może być mniejszy niż zastępowany ciąg ... dlatego nie trzeba przydzielać pamięci do wykonania zamiany. (Również na mikrokontrolerach możesz nie mieć nieskończonej pamięci i być może będziesz musiał wykonać wymianę na miejscu. Skopiuj wszystko do nowego bufora może nie być właściwym rozwiązaniem dla wszystkich ...)
Steven Spark
8
Oto przykładowy kod, który to robi.
#include<string.h>#include<stdlib.h>char * replace(
charconst * const original,
charconst * const pattern,
charconst * const replacement
){
size_tconst replen = strlen(replacement);
size_tconst patlen = strlen(pattern);
size_tconst orilen = strlen(original);
size_t patcnt = 0;
constchar * oriptr;
constchar * patloc;
// find how many times the pattern occurs in the original stringfor (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
patcnt++;
}
{
// allocate memory for the new stringsize_tconst retlen = orilen + patcnt * (replen - patlen);
char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );
if (returned != NULL)
{
// copy the original string, // replacing all the instances of the patternchar * retptr = returned;
for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
{
size_tconst skplen = patloc - oriptr;
// copy the section until the occurence of the patternstrncpy(retptr, oriptr, skplen);
retptr += skplen;
// copy the replacement strncpy(retptr, replacement, replen);
retptr += replen;
}
// copy the rest of the string.strcpy(retptr, oriptr);
}
return returned;
}
}
#include<stdio.h>intmain(int argc, char * argv[]){
if (argc != 4)
{
fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]);
exit(-1);
}
else
{
char * const newstr = replace(argv[1], argv[2], argv[3]);
if (newstr)
{
printf("%s\n", newstr);
free(newstr);
}
else
{
fprintf(stderr,"allocation error\n");
exit(-2);
}
}
return0;
}
Działa, ale jest trochę wadliwy, ale i tak dzięki! : D tutaj jest taki, który uważam za który działa bardzo dobrze, coding.debuntu.org/ ... na zdrowie! :)
Joe DF
4
// Here is the code for unicode strings!intmystrstr(wchar_t *txt1,wchar_t *txt2){
wchar_t *posstr=wcsstr(txt1,txt2);
if(posstr!=NULL)
{
return (posstr-txt1);
}else
{
return-1;
}
}
// assume: supplied buff is enough to hold generated textvoidStringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2){
wchar_t *tmp;
wchar_t *nextStr;
int pos;
tmp=wcsdup(buff);
pos=mystrstr(tmp,txt1);
if(pos!=-1)
{
buff[0]=0;
wcsncpy(buff,tmp,pos);
buff[pos]=0;
wcscat(buff,txt2);
nextStr=tmp+pos+wcslen(txt1);
while(wcslen(nextStr)!=0)
{
pos=mystrstr(nextStr,txt1);
if(pos==-1)
{
wcscat(buff,nextStr);
break;
}
wcsncat(buff,nextStr,pos);
wcscat(buff,txt2);
nextStr=nextStr+pos+wcslen(txt1);
}
}
free(tmp);
}
Funkcja repl_str () w serwisie creativeandcritical.net jest szybka i niezawodna. Na tej stronie znajduje się również wariant z szerokim ciągiem, repl_wcs () , który może być używany z ciągami znaków Unicode, w tym kodowanymi w UTF-8, poprzez funkcje pomocnicze - kod demonstracyjny jest linkowany ze strony. Spóźnione pełne ujawnienie informacji: jestem autorem tej strony i zawartych na niej funkcji.
szybki i niezawodny, ale ma ogromny wyciek pamięci.
MightyPork
3
Nie wiem, jak to się stało. Jest tylko jeden malloc, a dzwoniący jest instruowany, aby zwolnić pamięć, gdy nie jest już potrzebna. Możesz być bardziej dokładny?
Laird
@Lairdpos_cache = realloc(pos_cache
PSkocik
@PSkocik Funkcja została zaktualizowana od czasu skargi przez @MightyPork, ale mimo że ma teraz dodatkowe malloc / realloc dla pos_cache, nie widzę ścieżki kodu, która omija free(pos_cache);koniec funkcji.
Laird
@Laird reallocmoże zawieść. Jeśli tak się stanie, zwraca NULLi pozostawia stary wskaźnik nietknięty. p = realloc(p, x)will, w przypadku niepowodzenia, przepisze prawidłowy wskaźnik sterty za ppomocą NULL, a jeśli to pbyło twoje jedyne odniesienie do tego obiektu sterty, teraz to wyciekłeś. To klasyczny błąd początkujących.
PSkocik
3
Uważam, że większość proponowanych funkcji jest trudna do zrozumienia - więc wymyśliłem to:
staticchar *dull_replace(constchar *in, constchar *pattern, constchar *by){
size_t outsize = strlen(in) + 1;
// TODO maybe avoid reallocing by counting the non-overlapping occurences of patternchar *res = malloc(outsize);
// use this to iterate over the outputsize_t resoffset = 0;
char *needle;
while (needle = strstr(in, pattern)) {
// copy everything up to the patternmemcpy(res + resoffset, in, needle - in);
resoffset += needle - in;
// skip the pattern in the input-string
in = needle + strlen(pattern);
// adjust space for replacement
outsize = outsize - strlen(pattern) + strlen(by);
res = realloc(res, outsize);
// copy the patternmemcpy(res + resoffset, by, strlen(by));
resoffset += strlen(by);
}
// copy the remaining inputstrcpy(res + resoffset, in);
return res;
}
Możesz użyć tej funkcji (komentarze wyjaśniają, jak to działa):
voidstrreplace(char *string, constchar *find, constchar *replaceWith){
if(strstr(string, replaceWith) != NULL){
char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1);
strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part
*strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial stringstrcat(string, replaceWith); //Concat the first part of the string with the part to replace withstrcat(string, temporaryString); //Concat the first part of the string with the part after the replaced partfree(temporaryString); //Free the memory to avoid memory leaks
}
}
Oto ten, który stworzyłem na podstawie tych wymagań:
Wymień wzór niezależnie od tego, czy był długi, czy krótszy.
Nie używaj żadnego malloc (jawnego lub niejawnego), aby wewnętrznie uniknąć wycieków pamięci.
Zastąp dowolną liczbę wystąpień wzoru.
Toleruj ciąg zastępujący mający podłańcuch równy ciągowi wyszukiwania.
Nie musi sprawdzać, czy macierz Line ma wystarczający rozmiar, aby pomieścić zamiennik. np. to nie działa, chyba że dzwoniący wie, że linia jest wystarczająca do przechowywania nowego ciągu.
poprawka odpowiedzi fann95, przy użyciu modyfikacji łańcucha w miejscu i przy założeniu, że bufor wskazywany przez linię jest wystarczająco duży, aby pomieścić otrzymany ciąg.
staticvoidreplacestr(char *line, constchar *search, constchar *replace){
char *sp;
if ((sp = strstr(line, search)) == NULL) {
return;
}
int search_len = strlen(search);
int replace_len = strlen(replace);
int tail_len = strlen(sp+search_len);
memmove(sp+replace_len,sp+search_len,tail_len+1);
memcpy(sp, replace, replace_len);
}
Exmaple Usage
char s[]="this is a trial string to test the function.";
char x=' ', y='_';
printf("%s\n",zStrrep(s,x,y));
Example Output
this_is_a_trial_string_to_test_the_function.
EDYCJA: @siride ma rację, powyższa funkcja zastępuje tylko znaki. Właśnie napisałem ten, który zastępuje ciągi znaków.
#include<stdio.h>#include<stdlib.h>/* replace every occurance of string x with string y */char *zstring_replace_str(char *str, constchar *x, constchar *y){
char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y;
int len_str=0, len_y=0, len_x=0;
/* string length */for(; *tmp_y; ++len_y, ++tmp_y)
;
for(; *tmp_str; ++len_str, ++tmp_str)
;
for(; *tmp_x; ++len_x, ++tmp_x)
;
/* Bounds check */if (len_y >= len_str)
return str;
/* reset tmp pointers */
tmp_y = y;
tmp_x = x;
for (tmp_str = str ; *tmp_str; ++tmp_str)
if(*tmp_str == *tmp_x) {
/* save tmp_str */for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr)
if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){
/* Reached end of x, we got something to replace then!
* Copy y only if there is enough room for it
*/for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str)
*tmp_str = *tmp_y;
}
/* reset tmp_x */
tmp_x = x;
}
return str;
}
intmain(){
char s[]="Free software is a matter of liberty, not price.\n""To understand the concept, you should think of 'free' \n""as in 'free speech', not as in 'free beer'";
printf("%s\n\n",s);
printf("%s\n",zstring_replace_str(s,"ree","XYZ"));
return0;
}
A poniżej jest wyjście
Free software is a matter of liberty, not price.
To understand the concept, you should think of 'free'
as in 'free speech', not as in 'free beer'
FXYZ software is a matter of liberty, not price.
To understand the concept, you should think of 'fXYZ'
as in 'fXYZ speech', not as in 'fXYZ beer'
char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace withint replen = strlen(rep),repwlen = strlen(repw),count;//some constant variablesfor(int i=0;i<strlen(text);i++){//search for the first character from rep in textif(text[i] == rep[0]){//if it found it
count = 1;//start searching from the next character to avoid repetitionfor(int j=1;j<replen;j++){
if(text[i+j] == rep[j]){//see if the next character in text is the same as the next in the rep if not break
count++;
}else{
break;
}
}
if(count == replen){//if count equals to the lenght of the rep then we found the word that we want to replace in the textif(replen < repwlen){
for(int l = strlen(text);l>i;l--){//cuz repwlen greater than replen we need to shift characters to the right to make space for the replacement to fit
text[l+repwlen-replen] = text[l];//shift by repwlen-replen
}
}
if(replen > repwlen){
for(int l=i+replen-repwlen;l<strlen(text);l++){//cuz replen greater than repwlen we need to shift the characters to the left
text[l-(replen-repwlen)] = text[l];//shift by replen-repwlen
}
text[strlen(text)-(replen-repwlen)] = '\0';//get rid of the last unwanted characters
}
for(int l=0;l<repwlen;l++){//replace rep with repwlen
text[i+l] = repw[l];
}
if(replen != repwlen){
i+=repwlen-1;//pass to the next character | try text "y" ,rep "y",repw "yy" without this line to understand
}
}
}
}
return text;
}
jeśli chcesz, aby kod strlen unikał wywoływania string.h
intstrlen(char * string){//use this code to avoid calling string.hint lenght = 0;
while(string[lenght] != '\0'){
lenght++;
}
return lenght;
}
Odpowiedzi:
Optymalizator powinien wyeliminować większość zmiennych lokalnych. Wskaźnik tmp jest po to, aby upewnić się, że strcpy nie musi przechodzić przez łańcuch, aby znaleźć wartość null. tmp wskazuje koniec wyniku po każdym wywołaniu. (Zobacz algorytm malarza Shlemiela, aby dowiedzieć się, dlaczego strcpy może być denerwujący).
// You must free the result if result is non-NULL. char *str_replace(char *orig, char *rep, char *with) { char *result; // the return string char *ins; // the next insert point char *tmp; // varies int len_rep; // length of rep (the string to remove) int len_with; // length of with (the string to replace rep with) int len_front; // distance between rep and end of last rep int count; // number of replacements // sanity checks and initialization if (!orig || !rep) return NULL; len_rep = strlen(rep); if (len_rep == 0) return NULL; // empty rep causes infinite loop during count if (!with) with = ""; len_with = strlen(with); // count the number of replacements needed ins = orig; for (count = 0; tmp = strstr(ins, rep); ++count) { ins = tmp + len_rep; } tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1); if (!result) return NULL; // first time through the loop, all the variable are set correctly // from here on, // tmp points to the end of the result string // ins points to the next occurrence of rep in orig // orig points to the remainder of orig after "end of rep" while (count--) { ins = strstr(orig, rep); len_front = ins - orig; tmp = strncpy(tmp, orig, len_front) + len_front; tmp = strcpy(tmp, with) + len_with; orig += len_front + len_rep; // move to next "end of rep" } strcpy(tmp, orig); return result; }
źródło
size_t
zamiastint
dla dowolnych rozmiarów obiektów / ciągów i indeksów do nich. Jaki jest celstrcpy(tmp, orig);
na samym końcu? Wydaje się źle.for
pętlę można zamienić nafor (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}
, a następnietmp
służy ona tylko do pisania.Nie jest to zapewnione w standardowej bibliotece C, ponieważ podając tylko znak * nie można zwiększyć pamięci przydzielonej do ciągu, jeśli zastępujący ciąg jest dłuższy niż zastępowany ciąg.
Możesz to zrobić łatwiej, używając std :: string, ale nawet tam żadna funkcja nie zrobi tego za Ciebie.
źródło
Nie ma takiego.
Musiałbyś stworzyć własny, używając czegoś takiego jak strstr i strcat lub strcpy.
źródło
strcat()
to zła sugestia.Możesz zbudować własną funkcję zamiany, używając strstr, aby znaleźć podciągi i strncpy do skopiowania części do nowego bufora.
O ile to, co chcesz,
replace_with
ma taką samą długość, jak chceszreplace
, to prawdopodobnie najlepiej jest użyć nowego bufora do skopiowania nowego ciągu.źródło
Ponieważ łańcuchy w C nie mogą dynamicznie rosnąć, podstawianie w miejscu generalnie nie będzie działać. Dlatego musisz przydzielić miejsce na nowy ciąg, który ma wystarczająco dużo miejsca na twoje podstawienie, a następnie skopiować części z oryginału wraz z podstawieniem do nowego ciągu. Aby skopiować części, użyłbyś strncpy .
źródło
Oto przykładowy kod, który to robi.
#include <string.h> #include <stdlib.h> char * replace( char const * const original, char const * const pattern, char const * const replacement ) { size_t const replen = strlen(replacement); size_t const patlen = strlen(pattern); size_t const orilen = strlen(original); size_t patcnt = 0; const char * oriptr; const char * patloc; // find how many times the pattern occurs in the original string for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) { patcnt++; } { // allocate memory for the new string size_t const retlen = orilen + patcnt * (replen - patlen); char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) ); if (returned != NULL) { // copy the original string, // replacing all the instances of the pattern char * retptr = returned; for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen) { size_t const skplen = patloc - oriptr; // copy the section until the occurence of the pattern strncpy(retptr, oriptr, skplen); retptr += skplen; // copy the replacement strncpy(retptr, replacement, replen); retptr += replen; } // copy the rest of the string. strcpy(retptr, oriptr); } return returned; } } #include <stdio.h> int main(int argc, char * argv[]) { if (argc != 4) { fprintf(stderr,"usage: %s <original text> <pattern> <replacement>\n", argv[0]); exit(-1); } else { char * const newstr = replace(argv[1], argv[2], argv[3]); if (newstr) { printf("%s\n", newstr); free(newstr); } else { fprintf(stderr,"allocation error\n"); exit(-2); } } return 0; }
źródło
// Here is the code for unicode strings! int mystrstr(wchar_t *txt1,wchar_t *txt2) { wchar_t *posstr=wcsstr(txt1,txt2); if(posstr!=NULL) { return (posstr-txt1); }else { return -1; } } // assume: supplied buff is enough to hold generated text void StringReplace(wchar_t *buff,wchar_t *txt1,wchar_t *txt2) { wchar_t *tmp; wchar_t *nextStr; int pos; tmp=wcsdup(buff); pos=mystrstr(tmp,txt1); if(pos!=-1) { buff[0]=0; wcsncpy(buff,tmp,pos); buff[pos]=0; wcscat(buff,txt2); nextStr=tmp+pos+wcslen(txt1); while(wcslen(nextStr)!=0) { pos=mystrstr(nextStr,txt1); if(pos==-1) { wcscat(buff,nextStr); break; } wcsncat(buff,nextStr,pos); wcscat(buff,txt2); nextStr=nextStr+pos+wcslen(txt1); } } free(tmp); }
źródło
Funkcja repl_str () w serwisie creativeandcritical.net jest szybka i niezawodna. Na tej stronie znajduje się również wariant z szerokim ciągiem, repl_wcs () , który może być używany z ciągami znaków Unicode, w tym kodowanymi w UTF-8, poprzez funkcje pomocnicze - kod demonstracyjny jest linkowany ze strony. Spóźnione pełne ujawnienie informacji: jestem autorem tej strony i zawartych na niej funkcji.
źródło
pos_cache = realloc(pos_cache
free(pos_cache);
koniec funkcji.realloc
może zawieść. Jeśli tak się stanie, zwracaNULL
i pozostawia stary wskaźnik nietknięty.p = realloc(p, x)
will, w przypadku niepowodzenia, przepisze prawidłowy wskaźnik sterty zap
pomocąNULL
, a jeśli top
było twoje jedyne odniesienie do tego obiektu sterty, teraz to wyciekłeś. To klasyczny błąd początkujących.Uważam, że większość proponowanych funkcji jest trudna do zrozumienia - więc wymyśliłem to:
static char *dull_replace(const char *in, const char *pattern, const char *by) { size_t outsize = strlen(in) + 1; // TODO maybe avoid reallocing by counting the non-overlapping occurences of pattern char *res = malloc(outsize); // use this to iterate over the output size_t resoffset = 0; char *needle; while (needle = strstr(in, pattern)) { // copy everything up to the pattern memcpy(res + resoffset, in, needle - in); resoffset += needle - in; // skip the pattern in the input-string in = needle + strlen(pattern); // adjust space for replacement outsize = outsize - strlen(pattern) + strlen(by); res = realloc(res, outsize); // copy the pattern memcpy(res + resoffset, by, strlen(by)); resoffset += strlen(by); } // copy the remaining input strcpy(res + resoffset, in); return res; }
wyjście musi być wolne
źródło
Możesz użyć tej funkcji (komentarze wyjaśniają, jak to działa):
void strreplace(char *string, const char *find, const char *replaceWith){ if(strstr(string, replaceWith) != NULL){ char *temporaryString = malloc(strlen(strstr(string, find) + strlen(find)) + 1); strcpy(temporaryString, strstr(string, find) + strlen(find)); //Create a string with what's after the replaced part *strstr(string, find) = '\0'; //Take away the part to replace and the part after it in the initial string strcat(string, replaceWith); //Concat the first part of the string with the part to replace with strcat(string, temporaryString); //Concat the first part of the string with the part after the replaced part free(temporaryString); //Free the memory to avoid memory leaks } }
źródło
Oto ten, który stworzyłem na podstawie tych wymagań:
Wymień wzór niezależnie od tego, czy był długi, czy krótszy.
Nie używaj żadnego malloc (jawnego lub niejawnego), aby wewnętrznie uniknąć wycieków pamięci.
Zastąp dowolną liczbę wystąpień wzoru.
Toleruj ciąg zastępujący mający podłańcuch równy ciągowi wyszukiwania.
Nie musi sprawdzać, czy macierz Line ma wystarczający rozmiar, aby pomieścić zamiennik. np. to nie działa, chyba że dzwoniący wie, że linia jest wystarczająca do przechowywania nowego ciągu.
/* returns number of strings replaced. */ int replacestr(char *line, const char *search, const char *replace) { int count; char *sp; // start of pattern //printf("replacestr(%s, %s, %s)\n", line, search, replace); if ((sp = strstr(line, search)) == NULL) { return(0); } count = 1; int sLen = strlen(search); int rLen = strlen(replace); if (sLen > rLen) { // move from right to left char *src = sp + sLen; char *dst = sp + rLen; while((*dst = *src) != '\0') { dst++; src++; } } else if (sLen < rLen) { // move from left to right int tLen = strlen(sp) - sLen; char *stop = sp + rLen; char *src = sp + sLen + tLen; char *dst = sp + rLen + tLen; while(dst >= stop) { *dst = *src; dst--; src--; } } memcpy(sp, replace, rLen); count += replacestr(sp + rLen, search, replace); return(count); }
Wszelkie sugestie dotyczące ulepszenia tego kodu są mile widziane. Po prostu opublikuj komentarz, a ja go przetestuję.
źródło
Oto moje, spraw, aby wszystkie były zwęglone *, co ułatwia dzwonienie ...
char *strrpc(char *str,char *oldstr,char *newstr){ char bstr[strlen(str)]; memset(bstr,0,sizeof(bstr)); int i; for(i = 0;i < strlen(str);i++){ if(!strncmp(str+i,oldstr,strlen(oldstr))){ strcat(bstr,newstr); i += strlen(oldstr) - 1; }else{ strncat(bstr,str + i,1); } } strcpy(str,bstr); return str; }
źródło
Możesz użyć strrep ()
char * strrep (const char * cadena, const char * strf, const char * strr)
strrep (zastąpienie ciągu). Zamienia „strf” na „strr” w „cadena” i zwraca nowy ciąg. Musisz zwolnić zwrócony ciąg w kodzie po użyciu strrep.
Parametry cadena Ciąg z tekstem. strf Tekst do znalezienia. strr Tekst zastępczy.
Zwroty Tekst zaktualizowany z wymianą.
Projekt można znaleźć pod adresem https://github.com/ipserc/strrep
źródło
poprawka odpowiedzi fann95, przy użyciu modyfikacji łańcucha w miejscu i przy założeniu, że bufor wskazywany przez linię jest wystarczająco duży, aby pomieścić otrzymany ciąg.
static void replacestr(char *line, const char *search, const char *replace) { char *sp; if ((sp = strstr(line, search)) == NULL) { return; } int search_len = strlen(search); int replace_len = strlen(replace); int tail_len = strlen(sp+search_len); memmove(sp+replace_len,sp+search_len,tail_len+1); memcpy(sp, replace, replace_len); }
źródło
Nie idziesz .... to jest funkcja zastąpić każde wystąpienie
char x
zchar y
wewnątrz łańcucha znakówstr
char *zStrrep(char *str, char x, char y){ char *tmp=str; while(*tmp) if(*tmp == x) *tmp++ = y; /* assign first, then incement */ else *tmp++; *tmp='\0'; return str; }
Przykładem użycia może być
Exmaple Usage char s[]="this is a trial string to test the function."; char x=' ', y='_'; printf("%s\n",zStrrep(s,x,y)); Example Output this_is_a_trial_string_to_test_the_function.
Funkcja pochodzi z biblioteki ciągów, którą utrzymuję na Githubie , serdecznie zapraszamy do obejrzenia innych dostępnych funkcji, a nawet do współtworzenia kodu :)
https://github.com/fnoyanisi/zString
EDYCJA: @siride ma rację, powyższa funkcja zastępuje tylko znaki. Właśnie napisałem ten, który zastępuje ciągi znaków.
#include <stdio.h> #include <stdlib.h> /* replace every occurance of string x with string y */ char *zstring_replace_str(char *str, const char *x, const char *y){ char *tmp_str = str, *tmp_x = x, *dummy_ptr = tmp_x, *tmp_y = y; int len_str=0, len_y=0, len_x=0; /* string length */ for(; *tmp_y; ++len_y, ++tmp_y) ; for(; *tmp_str; ++len_str, ++tmp_str) ; for(; *tmp_x; ++len_x, ++tmp_x) ; /* Bounds check */ if (len_y >= len_str) return str; /* reset tmp pointers */ tmp_y = y; tmp_x = x; for (tmp_str = str ; *tmp_str; ++tmp_str) if(*tmp_str == *tmp_x) { /* save tmp_str */ for (dummy_ptr=tmp_str; *dummy_ptr == *tmp_x; ++tmp_x, ++dummy_ptr) if (*(tmp_x+1) == '\0' && ((dummy_ptr-str+len_y) < len_str)){ /* Reached end of x, we got something to replace then! * Copy y only if there is enough room for it */ for(tmp_y=y; *tmp_y; ++tmp_y, ++tmp_str) *tmp_str = *tmp_y; } /* reset tmp_x */ tmp_x = x; } return str; } int main() { char s[]="Free software is a matter of liberty, not price.\n" "To understand the concept, you should think of 'free' \n" "as in 'free speech', not as in 'free beer'"; printf("%s\n\n",s); printf("%s\n",zstring_replace_str(s,"ree","XYZ")); return 0; }
A poniżej jest wyjście
Free software is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech', not as in 'free beer' FXYZ software is a matter of liberty, not price. To understand the concept, you should think of 'fXYZ' as in 'fXYZ speech', not as in 'fXYZ beer'
źródło
/*замена символа в строке*/ char* replace_char(char* str, char in, char out) { char * p = str; while(p != '\0') { if(*p == in) *p == out; ++p; } return str; }
źródło
DWORD ReplaceString(__inout PCHAR source, __in DWORD dwSourceLen, __in const char* pszTextToReplace, __in const char* pszReplaceWith) { DWORD dwRC = NO_ERROR; PCHAR foundSeq = NULL; PCHAR restOfString = NULL; PCHAR searchStart = source; size_t szReplStrcLen = strlen(pszReplaceWith), szRestOfStringLen = 0, sztextToReplaceLen = strlen(pszTextToReplace), remainingSpace = 0, dwSpaceRequired = 0; if (strcmp(pszTextToReplace, "") == 0) dwRC = ERROR_INVALID_PARAMETER; else if (strcmp(pszTextToReplace, pszReplaceWith) != 0) { do { foundSeq = strstr(searchStart, pszTextToReplace); if (foundSeq) { szRestOfStringLen = (strlen(foundSeq) - sztextToReplaceLen) + 1; remainingSpace = dwSourceLen - (foundSeq - source); dwSpaceRequired = szReplStrcLen + (szRestOfStringLen); if (dwSpaceRequired > remainingSpace) { dwRC = ERROR_MORE_DATA; } else { restOfString = CMNUTIL_calloc(szRestOfStringLen, sizeof(CHAR)); strcpy_s(restOfString, szRestOfStringLen, foundSeq + sztextToReplaceLen); strcpy_s(foundSeq, remainingSpace, pszReplaceWith); strcat_s(foundSeq, remainingSpace, restOfString); } CMNUTIL_free(restOfString); searchStart = foundSeq + szReplStrcLen; //search in the remaining str. (avoid loops when replWith contains textToRepl } } while (foundSeq && dwRC == NO_ERROR); } return dwRC; }
źródło
char *replace(const char*instring, const char *old_part, const char *new_part) { #ifndef EXPECTED_REPLACEMENTS #define EXPECTED_REPLACEMENTS 100 #endif if(!instring || !old_part || !new_part) { return (char*)NULL; } size_t instring_len=strlen(instring); size_t new_len=strlen(new_part); size_t old_len=strlen(old_part); if(instring_len<old_len || old_len==0) { return (char*)NULL; } const char *in=instring; const char *found=NULL; size_t count=0; size_t out=0; size_t ax=0; char *outstring=NULL; if(new_len> old_len ) { size_t Diff=EXPECTED_REPLACEMENTS*(new_len-old_len); size_t outstring_len=instring_len + Diff; outstring =(char*) malloc(outstring_len); if(!outstring){ return (char*)NULL; } while((found = strstr(in, old_part))!=NULL) { if(count==EXPECTED_REPLACEMENTS) { outstring_len+=Diff; if((outstring=realloc(outstring,outstring_len))==NULL) { return (char*)NULL; } count=0; } ax=found-in; strncpy(outstring+out,in,ax); out+=ax; strncpy(outstring+out,new_part,new_len); out+=new_len; in=found+old_len; count++; } } else { outstring =(char*) malloc(instring_len); if(!outstring){ return (char*)NULL; } while((found = strstr(in, old_part))!=NULL) { ax=found-in; strncpy(outstring+out,in,ax); out+=ax; strncpy(outstring+out,new_part,new_len); out+=new_len; in=found+old_len; } } ax=(instring+instring_len)-in; strncpy(outstring+out,in,ax); out+=ax; outstring[out]='\0'; return outstring; }
źródło
Ta funkcja działa tylko wtedy, gdy łańcuch ur ma dodatkowe miejsce na nową długość
void replace_str(char *str,char *org,char *rep) { char *ToRep = strstr(str,org); char *Rest = (char*)malloc(strlen(ToRep)); strcpy(Rest,((ToRep)+strlen(org))); strcpy(ToRep,rep); strcat(ToRep,Rest); free(Rest); }
To zastępuje tylko pierwsze wystąpienie
źródło
Oto mój, jest samowystarczalny i wszechstronny, a także wydajny, rośnie lub zmniejsza bufory w zależności od potrzeb w każdej rekursji
void strreplace(char *src, char *str, char *rep) { char *p = strstr(src, str); if (p) { int len = strlen(src)+strlen(rep)-strlen(str); char r[len]; memset(r, 0, len); if ( p >= src ){ strncpy(r, src, p-src); r[p-src]='\0'; strncat(r, rep, strlen(rep)); strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src)); strcpy(src, r); strreplace(p+strlen(rep), str, rep); } } }
źródło
Używając tylko strlen z string.h
przepraszam za mój angielski
char * str_replace(char * text,char * rep, char * repw){//text -> to replace in it | rep -> replace | repw -> replace with int replen = strlen(rep),repwlen = strlen(repw),count;//some constant variables for(int i=0;i<strlen(text);i++){//search for the first character from rep in text if(text[i] == rep[0]){//if it found it count = 1;//start searching from the next character to avoid repetition for(int j=1;j<replen;j++){ if(text[i+j] == rep[j]){//see if the next character in text is the same as the next in the rep if not break count++; }else{ break; } } if(count == replen){//if count equals to the lenght of the rep then we found the word that we want to replace in the text if(replen < repwlen){ for(int l = strlen(text);l>i;l--){//cuz repwlen greater than replen we need to shift characters to the right to make space for the replacement to fit text[l+repwlen-replen] = text[l];//shift by repwlen-replen } } if(replen > repwlen){ for(int l=i+replen-repwlen;l<strlen(text);l++){//cuz replen greater than repwlen we need to shift the characters to the left text[l-(replen-repwlen)] = text[l];//shift by replen-repwlen } text[strlen(text)-(replen-repwlen)] = '\0';//get rid of the last unwanted characters } for(int l=0;l<repwlen;l++){//replace rep with repwlen text[i+l] = repw[l]; } if(replen != repwlen){ i+=repwlen-1;//pass to the next character | try text "y" ,rep "y",repw "yy" without this line to understand } } } } return text; }
jeśli chcesz, aby kod strlen unikał wywoływania string.h
int strlen(char * string){//use this code to avoid calling string.h int lenght = 0; while(string[lenght] != '\0'){ lenght++; } return lenght; }
źródło