Cho một char *
chuỗi ( ), tôi muốn tìm tất cả các lần xuất hiện của một chuỗi con và thay thế chúng bằng một chuỗi thay thế. Tôi không thấy bất kỳ chức năng đơn giản nào đạt được điều này trong <string.h>
.
Cho một char *
chuỗi ( ), tôi muốn tìm tất cả các lần xuất hiện của một chuỗi con và thay thế chúng bằng một chuỗi thay thế. Tôi không thấy bất kỳ chức năng đơn giản nào đạt được điều này trong <string.h>
.
Câu trả lời:
Trình tối ưu hóa sẽ loại bỏ hầu hết các biến cục bộ. Con trỏ tmp ở đó để đảm bảo strcpy không phải đi bộ chuỗi để tìm giá trị rỗng. tmp trỏ đến cuối kết quả sau mỗi cuộc gọi. (Xem Shlemiel thuật toán của họa sĩ để biết tại sao strcpy có thể gây phiền nhiễu.)
// 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;
}
size_t
thay vì int
cho các kích thước và chỉ số đối tượng / chuỗi tùy ý vào chúng. Ngoài ra, mục đích strcpy(tmp, orig);
cuối cùng là gì? Nó có vẻ sai.
for
vòng lặp đầu tiên đó bằng for (count = 1; ins = strstr(ins + rep_len, rep); ++count) {}
, sau đó tmp
chỉ được sử dụng để viết.
Điều này không được cung cấp trong thư viện C tiêu chuẩn bởi vì, chỉ được cung cấp một ký tự *, bạn không thể tăng bộ nhớ được cấp phát cho chuỗi nếu chuỗi thay thế dài hơn chuỗi được thay thế.
Bạn có thể làm điều này bằng cách sử dụng std :: string dễ dàng hơn, nhưng ngay cả khi ở đó, không có hàm đơn lẻ nào làm điều đó cho bạn.
Không có một.
Bạn cần phải cuộn của riêng bạn bằng cách sử dụng một cái gì đó như strstr và strcat hoặc strcpy.
strcat()
là một gợi ý không tồi.
Bạn có thể xây dựng hàm thay thế của riêng mình bằng cách sử dụng strstr để tìm các chuỗi con và strncpy để sao chép từng phần vào bộ đệm mới.
Trừ khi những gì bạn muốn replace_with
có cùng độ dài với những gì bạn muốn replace
, thì tốt nhất bạn nên sử dụng một bộ đệm mới để sao chép chuỗi mới vào.
Vì các chuỗi trong C không thể tự động phát triển thay thế thay thế thường sẽ không hoạt động. Do đó, bạn cần phải phân bổ không gian cho một chuỗi mới có đủ chỗ cho sự thay thế của bạn và sau đó sao chép các phần từ bản gốc cộng với phần thay thế vào chuỗi mới. Để sao chép các phần, bạn sẽ sử dụng strncpy .
Đây là một số mã mẫu thực hiện điều đó.
#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;
}
// 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);
}
Hàm repl_str () trên creativeandcritical.net rất nhanh và đáng tin cậy. Cũng được bao gồm trên trang đó là một biến thể chuỗi rộng, repl_wcs () , có thể được sử dụng với các chuỗi Unicode bao gồm những chuỗi được mã hóa bằng UTF-8, thông qua các hàm trợ giúp - mã demo được liên kết từ trang. Tiết lộ đầy đủ muộn màng: Tôi là tác giả của trang đó và các chức năng trên đó.
pos_cache = realloc(pos_cache
free(pos_cache);
cuối của hàm.
realloc
có thể bị lỗi. Nếu có, nó sẽ trả về NULL
và giữ nguyên con trỏ cũ. p = realloc(p, x)
sẽ, nếu xảy ra lỗi, viết lại một con trỏ đống hợp lệ p
với NULL
, và nếu điều đó p
là tài liệu tham khảo duy nhất của bạn với đối tượng heap, bây giờ bạn đã bị rò rỉ nó. Đó là một sai lầm cổ điển của người mới.
tôi thấy hầu hết các chức năng được đề xuất khó hiểu - vì vậy tôi đã nghĩ ra điều này:
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;
}
đầu ra phải được miễn phí
Bạn có thể sử dụng chức năng này (các nhận xét giải thích cách hoạt động):
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
}
}
Đây là cái mà tôi đã tạo dựa trên những yêu cầu sau:
Thay thế mẫu bất kể là dài hay ngắn hơn.
Không sử dụng bất kỳ malloc nào (rõ ràng hoặc ẩn) để tránh rò rỉ bộ nhớ về bản chất.
Thay thế bất kỳ số lần xuất hiện nào của mẫu.
Dung sai chuỗi thay thế có chuỗi con bằng chuỗi tìm kiếm.
Không phải kiểm tra xem Mảng dòng có đủ kích thước để chứa phần thay thế hay không. Ví dụ: Điều này không hoạt động trừ khi người gọi biết dòng đó có kích thước đủ để chứa chuỗi mới.
/* 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);
}
Bất kỳ đề xuất nào để cải thiện mã này đều được vui vẻ chấp nhận. Chỉ cần đăng bình luận và tôi sẽ kiểm tra nó.
Bạn có thể sử dụng strrep ()
char * strrep (const char * cadena, const char * strf, const char * strr)
strrep (Thay thế chuỗi). Thay thế 'strf' bằng 'strr' trong 'cadena' và trả về chuỗi mới. Bạn cần giải phóng chuỗi trả về trong mã của mình sau khi sử dụng strrep.
Tham số cadena Chuỗi có văn bản. strf Văn bản cần tìm. strr Văn bản thay thế.
Trả về Văn bản được cập nhật với sự thay thế.
Dự án có thể được tìm thấy tại https://github.com/ipserc/strrep
bản sửa lỗi cho phản hồi của fann95, sử dụng sửa đổi tại chỗ của chuỗi và giả sử bộ đệm được trỏ đến từng dòng đủ lớn để chứa chuỗi kết quả.
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);
}
Đây rồi .... đây là hàm để thay thế mọi lần xuất hiện char x
bằng char y
trong chuỗi ký tự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;
}
Một ví dụ sử dụng có thể là
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.
Hàm là từ một thư viện chuỗi mà tôi duy trì trên Github , rất hoan nghênh bạn xem qua các hàm có sẵn khác hoặc thậm chí đóng góp vào mã :)
https://github.com/fnoyanisi/zString
CHỈNH SỬA: @siride là đúng, hàm trên chỉ thay thế các ký tự. Vừa mới viết cái này, thay thế chuỗi ký tự.
#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;
}
Và dưới đây là đầu ra
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* replace_char(char* str, char in, char out) {
char * p = str;
while(p != '\0') {
if(*p == in)
*p == out;
++p;
}
return str;
}
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;
}
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;
}
Hàm này chỉ hoạt động nếu chuỗi của bạn có thêm không gian cho độ dài mới
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);
}
Điều này chỉ thay thế Lần xuất hiện đầu tiên
Đây là vấn đề của tôi, nó độc lập và linh hoạt, cũng như hiệu quả, nó phát triển hoặc thu nhỏ bộ đệm khi cần thiết trong mỗi lần đệ quy
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);
}
}
}
Đây là thông tin của tôi, hãy biến chúng thành tất cả các ký tự *, giúp việc gọi điện dễ dàng hơn ...
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;
}
Chỉ sử dụng strlen từ string.h
xin lỗi vì tiếng Anh của tôi
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;
}
nếu bạn muốn mã strlen để tránh gọi string.h
int strlen(char * string){//use this code to avoid calling string.h
int lenght = 0;
while(string[lenght] != '\0'){
lenght++;
}
return lenght;
}