C 对于字符串,查找并替换

C 对于字符串,查找并替换,c,algorithm,string-search,C,Algorithm,String Search,在C字符串中查找一些文本并用新文本替换它可能比预期的要复杂一些。 我正在寻找一种快速且时间复杂度小的算法 我应该使用什么?使用std::string(来自)您只需使用查找和替换 -给你一个索引 -获取索引 编辑:Touché。这是C++的。< /P> 这对你有好处吗? 克努斯·莫里斯·普拉特(经典)或博耶·摩尔(有时速度更快) 尝试使用Google搜索“字符串搜索算法”。我不禁想知道strstr()实现了什么算法。鉴于这些都是相当标准的算法,因此完全有可能一个好的strstr()实现

在C字符串中查找一些文本并用新文本替换它可能比预期的要复杂一些。 我正在寻找一种快速且时间复杂度小的算法


我应该使用什么?

使用
std::string
(来自
)您只需使用
查找
替换

  • -给你一个索引
  • -获取索引
编辑:Touché。这是C++的。< /P> 这对你有好处吗? 克努斯·莫里斯·普拉特(经典)或博耶·摩尔(有时速度更快)


尝试使用Google搜索“字符串搜索算法”。

我不禁想知道strstr()实现了什么算法。鉴于这些都是相当标准的算法,因此完全有可能一个好的strstr()实现使用其中一种算法

但是,不能保证strstr()实现了优化的算法,也不能保证从一个平台到另一个平台使用相同的算法。

下面是一段很好的代码

#include <stdio.h>
#include <string.h>

char *replace_str(char *str, char *orig, char *rep)
{
  static char buffer[4096];
  char *p;

  if(!(p = strstr(str, orig)))  // Is 'orig' even in 'str'?
    return str;

  strncpy(buffer, str, p-str); // Copy characters from 'str' start to 'orig' st$
  buffer[p-str] = '\0';

  sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));

  return buffer;
}

int main(void)
{
  puts(replace_str("Hello, world!", "world", "Miami"));

  return 0;
}
#包括
#包括
char*replace_str(char*str,char*orig,char*rep)
{
静态字符缓冲区[4096];
char*p;
if(!(p=strstrstr(str,orig))//在'str'中'orig'是偶数吗?
返回str;
strncpy(buffer,str,p-str);//将字符从'str'开始复制到'orig'st$
缓冲区[p-str]='\0';
sprintf(buffer+(p-str),%s%s,rep,p+strlen(orig));
返回缓冲区;
}
内部主(空)
{
放置(替换“你好,世界!”、“世界”、“迈阿密”);
返回0;
}

我找不到我喜欢的C语言中搜索/替换的实现,所以我在这里展示了我自己的。它不使用诸如strstr()、snprintf()、任意长度的临时缓冲区等。它只需要haystack缓冲区足够大,以便在进行替换后容纳生成的字符串

// str_replace(haystack, haystacksize, oldneedle, newneedle) --
//  Search haystack and replace all occurences of oldneedle with newneedle.
//  Resulting haystack contains no more than haystacksize characters (including the '\0').
//  If haystacksize is too small to make the replacements, do not modify haystack at all.
//
// RETURN VALUES
// str_replace() returns haystack on success and NULL on failure. 
// Failure means there was not enough room to replace all occurences of oldneedle.
// Success is returned otherwise, even if no replacement is made.
char *str_replace(char *haystack, size_t haystacksize,
                    const char *oldneedle, const char *newneedle);

// ------------------------------------------------------------------
// Implementation of function
// ------------------------------------------------------------------
#define SUCCESS (char *)haystack
#define FAILURE (void *)NULL

static bool
locate_forward(char **needle_ptr, char *read_ptr, 
        const char *needle, const char *needle_last);
static bool
locate_backward(char **needle_ptr, char *read_ptr, 
        const char *needle, const char *needle_last);

char *str_replace(char *haystack, size_t haystacksize,
                    const char *oldneedle, const char *newneedle)
{   
    size_t oldneedle_len = strlen(oldneedle);
    size_t newneedle_len = strlen(newneedle);
    char *oldneedle_ptr;    // locates occurences of oldneedle
    char *read_ptr;         // where to read in the haystack
    char *write_ptr;        // where to write in the haystack
    const char *oldneedle_last =  // the last character in oldneedle
        oldneedle +             
        oldneedle_len - 1;      

    // Case 0: oldneedle is empty
    if (oldneedle_len == 0)
        return SUCCESS;     // nothing to do; define as success

    // Case 1: newneedle is not longer than oldneedle
    if (newneedle_len <= oldneedle_len) {       
        // Pass 1: Perform copy/replace using read_ptr and write_ptr
        for (oldneedle_ptr = (char *)oldneedle,
            read_ptr = haystack, write_ptr = haystack; 
            *read_ptr != '\0';
            read_ptr++, write_ptr++)
        {
            *write_ptr = *read_ptr;         
            bool found = locate_forward(&oldneedle_ptr, read_ptr,
                        oldneedle, oldneedle_last);
            if (found)  {   
                // then perform update
                write_ptr -= oldneedle_len;
                memcpy(write_ptr+1, newneedle, newneedle_len);
                write_ptr += newneedle_len;
            }               
        } 
        *write_ptr = '\0';
        return SUCCESS;
    }

    // Case 2: newneedle is longer than oldneedle
    else {
        size_t diff_len =       // the amount of extra space needed 
            newneedle_len -     // to replace oldneedle with newneedle
            oldneedle_len;      // in the expanded haystack

        // Pass 1: Perform forward scan, updating write_ptr along the way
        for (oldneedle_ptr = (char *)oldneedle,
            read_ptr = haystack, write_ptr = haystack;
            *read_ptr != '\0';
            read_ptr++, write_ptr++)
        {
            bool found = locate_forward(&oldneedle_ptr, read_ptr, 
                        oldneedle, oldneedle_last);
            if (found) {    
                // then advance write_ptr
                write_ptr += diff_len;
            }
            if (write_ptr >= haystack+haystacksize)
                return FAILURE; // no more room in haystack
        }

        // Pass 2: Walk backwards through haystack, performing copy/replace
        for (oldneedle_ptr = (char *)oldneedle_last;
            write_ptr >= haystack;
            write_ptr--, read_ptr--)
        {
            *write_ptr = *read_ptr;
            bool found = locate_backward(&oldneedle_ptr, read_ptr, 
                        oldneedle, oldneedle_last);
            if (found) {    
                // then perform replacement
                write_ptr -= diff_len;
                memcpy(write_ptr, newneedle, newneedle_len);
            }   
        }
        return SUCCESS;
    }
}

// locate_forward: compare needle_ptr and read_ptr to see if a match occured
// needle_ptr is updated as appropriate for the next call
// return true if match occured, false otherwise
static inline bool 
locate_forward(char **needle_ptr, char *read_ptr,
        const char *needle, const char *needle_last)
{
    if (**needle_ptr == *read_ptr) {
        (*needle_ptr)++;
        if (*needle_ptr > needle_last) {
            *needle_ptr = (char *)needle;
            return true;
        }
    }
    else 
        *needle_ptr = (char *)needle;
    return false;
}

// locate_backward: compare needle_ptr and read_ptr to see if a match occured
// needle_ptr is updated as appropriate for the next call
// return true if match occured, false otherwise
static inline bool
locate_backward(char **needle_ptr, char *read_ptr, 
        const char *needle, const char *needle_last)
{
    if (**needle_ptr == *read_ptr) {
        (*needle_ptr)--;
        if (*needle_ptr < needle) {
            *needle_ptr = (char *)needle_last;
            return true;
        }
    }
    else 
        *needle_ptr = (char *)needle_last;
    return false;
}
输出 没有足够的空间将$USERNAME替换为“系统管理员”
你的名字是管理员


干杯。

我的解决方案基于其他解决方案,但我相信更安全一点:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SOURCE_SIZE (0x100000)

char * searchReplace(char * string, char *toReplace[], char *replacements[], int numReplacements){
    int i = 0;
    char *locOfToRep;
    char *toRep;
    char *rep;
    int lenToRep,lenStr,lenAfterLocRep;
    static char buffer[MAX_SOURCE_SIZE];
    for(i = 0; i < numReplacements; ++i){
        toRep = toReplace[i];
        rep = replacements[i];
        //if str not in the string, exit.
        if (!(locOfToRep = strstr(string,toRep))){
           exit(EXIT_FAILURE);
        }
        lenToRep = strlen(toRep); 
        lenStr = strlen(string); 
        lenAfterLocRep = strlen(locOfToRep); 

        //Print the string upto the pointer, then the val, and then the rest of the string.
        sprintf(buffer, "%.*s%s%s", lenStr-lenAfterLocRep, string,rep,locOfToRep+lenToRep);

        string = buffer;
    }
    return buffer;
}

int main(){
    char * string = "Hello, world!";
    int numVals;
    char *names[2] = {"Hello", "world"};
    char *vals[2] = {"Goodbye", "you"};
    numVals = 2;
    string = searchReplace(string, names, vals, numVals);
    printf("%s\n",string);
}
#包括
#包括
#包括
#定义最大源大小(0x100000)
char*searchReplace(char*string,char*toReplace[],char*replacements[],int numReplacements){
int i=0;
char*locOfToRep;
char*toRep;
char*rep;
int lenToRep、lenStr、lenAfterLocRep;
静态字符缓冲区[最大源大小];
对于(i=0;i OP要求C.和C++的代码> STD::String 由标准<>代码>代码>定义。对于将来寻找C和C++的人来说,这仍然是一个很好的答案。即使不能回答眼前的问题,为什么还要进行向下投票?与[字符串替换的最有效算法是什么?]相同()。正如上面提到的,一旦有了一个好的find算法,替换就非常简单了。你可能也会发现一些有用的方法。我在谷歌上搜索了一会儿,希望能找到一个实现列表。但没有这样的运气。有点奇怪,你不觉得吗?我确实发现了这一点:所以在这个glibc实现中,它显然是一个糟糕的算法。既然你知道要复制多少字节,为什么还要使用strncpy呢?memcpy()将更快,因为它不需要检查空终止符。类似地,sprintf将比两次调用memcpy和一次调用strlen慢得多。使用静态缓冲区会使此函数不可重入,并有缓冲区溢出的风险。如果strlen(rep)>strlen(orig)?put(replace_str(“Hello”,“Hellox”))是一个有趣的测试用例,您会怎么做。欢迎使用堆栈溢出。你的代码可以工作,这很好!做得好。为什么您的
paste()
函数比
memmove()
memcpy()更可取?当您调用它时,您知道所有长度,因此使用标准函数可能会做得更好。您可能应该在
oldneel
newneedle
参数中添加常量限定符。您的测试代码可以更加严格,并且应该覆盖空的旧针壳。这种行为并不明显;给你一根空针和一个空干草堆,你就得到了替代品;给你一根空针和一个不空的干草堆,你就得到了干草堆;我已经指出了这些要点——你说得对,不需要定制
paste()
函数
memcpy
是正确的选择。另外,如果oldneedle是空的,则只需始终执行相同的操作(无需替换)就更简单,而且希望更明显。我使用此算法测试了一些代码,发现如果长度完全正确(或者我的意思是错误的?),则代码将在haystack数组末尾之外写入一个字节。问题在于“案例2”代码中第一个(通过1)循环的情况。我将
条件修改为:
for(oldPionel\u ptr=(char*)oldPionel,read\u ptr=haystack,write\u ptr=haystack;*read\u ptr!='\0'&&write\u ptr
,如果(write\u ptr>=haystacksize)返回失败,则移动测试
在循环外。工作正常,但随着缓冲区变大,速度会变得非常慢。。。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_SOURCE_SIZE (0x100000)

char * searchReplace(char * string, char *toReplace[], char *replacements[], int numReplacements){
    int i = 0;
    char *locOfToRep;
    char *toRep;
    char *rep;
    int lenToRep,lenStr,lenAfterLocRep;
    static char buffer[MAX_SOURCE_SIZE];
    for(i = 0; i < numReplacements; ++i){
        toRep = toReplace[i];
        rep = replacements[i];
        //if str not in the string, exit.
        if (!(locOfToRep = strstr(string,toRep))){
           exit(EXIT_FAILURE);
        }
        lenToRep = strlen(toRep); 
        lenStr = strlen(string); 
        lenAfterLocRep = strlen(locOfToRep); 

        //Print the string upto the pointer, then the val, and then the rest of the string.
        sprintf(buffer, "%.*s%s%s", lenStr-lenAfterLocRep, string,rep,locOfToRep+lenToRep);

        string = buffer;
    }
    return buffer;
}

int main(){
    char * string = "Hello, world!";
    int numVals;
    char *names[2] = {"Hello", "world"};
    char *vals[2] = {"Goodbye", "you"};
    numVals = 2;
    string = searchReplace(string, names, vals, numVals);
    printf("%s\n",string);
}