Учитывая (char *
) строку, я хочу найти все вхождения подстроки и заменить их альтернативной строкой. Я не вижу какой-либо простой функции, которая достигает этого в <string.h>
.
Какова функция замены строки в C?
Ответ 1
Оптимизатор должен исключить большинство локальных переменных. Указатель tmp предназначен для того, чтобы strcpy не проходил строку, чтобы найти ноль. tmp указывает на конец результата после каждого вызова. (См. Алгоритм маляра Шлемеля, почему strcpy может раздражать.)
// 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;
}
Ответ 2
Это не предусмотрено в стандартной библиотеке C, поскольку, учитывая только char *, вы не можете увеличить память, выделенную для строки, если строка замены больше, чем заменяемая строка.
Вы можете сделать это с помощью std::string более легко, но даже там ни одна функция не сделает это для вас.
Ответ 3
Вы можете создать свою собственную функцию замены с помощью strstr, чтобы найти подстроки и strncpy для копирования по частям в новый буфер.
Если вы не хотите replace_with
совпадать с тем, что хотите, replace
, то лучше всего использовать новый буфер для копирования новой строки.
Ответ 4
Нет.
Вам нужно будет свернуть свое собственное, используя strstr и strcat или strcpy.
Ответ 5
Поскольку строки в C не могут динамически расти, замещение замещения в целом вообще не работает. Поэтому вам нужно выделить место для новой строки, в которой есть достаточно места для вашей замены, а затем скопируйте части из оригинала плюс замену в новую строку. Чтобы скопировать части, вы должны использовать strncpy.
Ответ 6
Вот пример кода, который это делает.
#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;
}
Ответ 7
// 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);
}
Ответ 8
Функция repl_str() на creativeandcritical.net является быстрой и надежной. Также на этой странице представлен широкий вариант строк, repl_wcs(), который может использоваться с строками Unicode, включая те, которые закодированы в UTF-8, через вспомогательные функции - демонстрационный код связан со страницей. Сдержанное полное раскрытие: я являюсь автором этой страницы и ее функций.
Ответ 9
я нахожу, что большинство предлагаемых функций трудно понять, поэтому я придумал следующее:
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;
}
выход должен быть свободен
Ответ 10
// replace every occurrence of a in str with b
void strrepl_inplace(char *str, const char *a, const char *b)
{
for (char *cursor=str; (cursor=strstr(cursor,a)) != NULL;)
{
memmove(cursor+strlen(b),cursor+strlen(a),strlen(cursor)-strlen(a)+1);
for (int i=0; b[i]!='\0'; i++)
{
cursor[i] = b[i];
}
cursor += strlen(b);
}
}
Это, возможно, лучшее, что вы могли бы сделать:
- всего 8 строк
- только 1 временный указатель
- модификация на месте
- работает с символами произвольного размера
a
иb
char*
- работает для удаления
если вы не хотите модифицировать на месте или вам нужно работать с const char*
, это еще одна версия той же функции, которая возвращает новый char * с выполненными изменениями. (не забудьте free
возвращаемое значение, так как strdup()
выполняет malloc
за сценой)
char* strrepl(const char *str, const char *a, const char *b)
{
char* strd = strdup(str);
return strrepl_inplace(strd,a,b);
}
Образец кода:
int main(int argc, char const *argv[])
{
char *a = strdup("Hello This Is Jack");
char *b = strrepl(a, " ", "~~~");
printf("Out-of-place modification : %s\n", b);
strrepl_inplace(a, "Jack", "Fourchette");
printf("In place modification : %s\n", a);
return 0;
}
Выход:
Out-of-place modification : Hello~~~This~~~Is~~~Jack
In place modification : Hello This Is Fourchette
Ответ 11
Вы можете использовать эту функцию (комментарии объясняют, как она работает):
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 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
}
}
Ответ 12
Вот тот, который я создал на основе этих требований:
-
Замените шаблон независимо от того, был ли он длинным или коротким.
-
Не использовать какой-либо malloc (явный или неявный), чтобы избежать утечек памяти.
-
Замените любое количество вхождений шаблона.
-
Допустим, что строка replace имеет подстроку, равную строке поиска.
-
Не нужно проверять, достаточен ли размер массива Line для хранения. например Это не работает, если вызывающий абонент не знает, что строка имеет достаточный размер для хранения новой строки.
/* 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);
}
Любые предложения по улучшению этого кода приветствуются. Просто опубликуйте комментарий, и я испытаю его.
Ответ 13
/*замена символа в строке*/
char* replace_char(char* str, char in, char out) {
char * p = str;
while(p != '\0') {
if(*p == in)
*p == out;
++p;
}
return str;
}
Ответ 14
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;
}
Ответ 15
исправление к ответу fann95, используя внутреннюю модификацию строки и предполагая, что буфер, на который указывает линия, достаточно велик, чтобы удерживать полученную строку.
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);
}
Ответ 16
Там вы идете... это функция, чтобы заменить каждую октаву char x
на char y
в строке символов str
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;
}
Пример использования может быть
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.
Функция из строковой библиотеки, которую я поддерживаю в Github, вы более чем можете взглянуть на другие доступные функции или даже внести свой вклад к коду:)
https://github.com/fnoyanisi/zString
EDIT: @siride прав, функция выше заменяет только символы. Просто написал этот, который заменяет символьные строки.
#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;
}
И ниже представлен вывод
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'
Ответ 17
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;
}
Ответ 18
Эта функция работает, только если в вашей строке есть дополнительное место для новой длины
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);
}
Это только заменяет первое вхождение
Ответ 19
Здесь мой, он самодостаточный и универсальный, а также эффективный, он увеличивает или уменьшает буферы по мере необходимости в каждой рекурсии
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);
}
}
}