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