D语言字符串替换优化:提升 replaceString 效率
D语言字符串替换优化:提升 replaceString 效率
在D语言中,replaceString 函数用于替换字符串中的子串,但其效率往往比较低。本文将介绍一种优化方案,通过使用标准库函数 strstr 和 strcasestr,以及对函数实现逻辑的改进,有效提升了代码效率,减少了运行时间。
优化思路
原来的 replaceString 函数实现方式是遍历整个字符串,逐个比较字符是否相等。这种方式在字符串很长的情况下效率很低。优化方案是:
-
利用标准库函数
strstr和strcasestr:strstr函数用于在字符串中查找第一个匹配的子串,strcasestr函数则不区分大小写。根据isCaseSensitive参数,选择合适的函数进行查找,可以显著提高查找效率。 -
判断查找结果是否在单词边界上:当
isCaseSensitive为false时,需要判断查找结果是否在单词边界上。如果不在单词边界上,则继续查找下一个匹配的子串。
优化后的代码
import std.stdio;
import core.stdc.stdio:printf;
import core.stdc.string;
import core.stdc.stdlib : malloc, free;
import core.stdc.ctype:tolower;
import std:toUTFz;
import std.string:fromStringz,toStringz;
import std.datetime;
// 判断两个字符是否相等,根据 isCaseSensitive 参数决定是否区分大小写
private bool charEqual(char a, char b, bool isCaseSensitive) @nogc nothrow
{
if (isCaseSensitive)
{
return a == b;
}
else
{
return tolower(a) == tolower(b);
}
}
// 在字符串 haystack 中查找第一次出现 needle 的位置,返回指向该位置的指针,如果找不到则返回 null
private char* strstrCase(char* haystack, const char* needle, bool isCaseSensitive) @nogc nothrow
{
if (!haystack || !needle || !*needle)
{
return haystack;
}
size_t haystackLen = strlen(haystack);
size_t needleLen = strlen(needle);
if (needleLen > haystackLen)
{
return null;
}
if (isCaseSensitive)
{
return strstr(haystack, needle);
}
else
{
char* p = haystack;
while ((p = strcasestr(p, needle)) != null)
{
// 判断找到的位置是否在单词边界上
if ((p == haystack || !isalpha(*(p - 1))) && !isalpha(*(p + needleLen)))
{
return p;
}
p += needleLen;
}
return null;
}
}
char* replaceCstr(char* allStr, const char* searchStr, const char* replaceStr, bool isCaseSensitive=true) @nogc nothrow
{
if (!allStr || !searchStr || !replaceStr || !*searchStr)
{
return allStr;
}
char* result = null;
ulong searchStrLength = strlen(searchStr);
ulong replaceStrLength = strlen(replaceStr);
ulong count = 0;
char* p = allStr;
while ((p = strstrCase(p, searchStr, isCaseSensitive)) != null)
{
count++;
p += searchStrLength;
}
if (count == 0)
{
return allStr;
}
ulong newStrLength = strlen(allStr) + count * (replaceStrLength - searchStrLength);
result = cast(char*) malloc(newStrLength + 1);
char* q = result;
p = allStr;
while (count-- > 0)
{
char* r = strstrCase(p, searchStr, isCaseSensitive);
long length = r - p;
memmove(q, p, length);
q += length;
memcpy(q, replaceStr, replaceStrLength);
q += replaceStrLength;
p = r + searchStrLength;
}
strcpy(q, p);
return result;
}
ref T replaceString(T)(auto ref T allStr,auto ref T searchStr,auto ref T replaceStr, bool isCaseSensitive=true)
{
static if(is(T==wstring))
{
long index = 0;
while ((index = isCaseSensitive ? allStr.indexOf(searchStr, index) : allStr.toLowerAll().indexOf(searchStr.toLowerAll(), index)) != -1)
{
allStr = allStr[0 .. index] ~ replaceStr ~ allStr[index + searchStr.length .. $];
index += replaceStr.length;
}
return allStr;
}
else static if(is(T==string))
{
auto allStrPtr = toUTFz!(char*)(allStr);
auto searchStrPtr = searchStr.ptr;
auto replaceStrPtr = replaceStr.ptr;
char* result = null;
if (isCaseSensitive)
{
result = replaceCstr(allStrPtr, searchStrPtr, replaceStrPtr, true);
}
else
{
// 先复制一份原始字符串
char* tempStr = cast(char*) malloc(strlen(allStrPtr) + 1);
strcpy(tempStr, allStrPtr);
// 用 strcasestr 查找子串并替换
char* p = tempStr;
while ((p = strstrCase(p, searchStrPtr, false)) != null)
{
char* q = result ? result + strlen(result) : allStrPtr;
size_t length = p - tempStr;
// 复制替换前的部分
memmove(q, tempStr, length);
q += length;
// 复制替换后的部分
memcpy(q, replaceStrPtr, strlen(replaceStrPtr));
q += strlen(replaceStrPtr);
// 更新指针和长度
p += strlen(searchStrPtr);
tempStr = p;
// 重新分配内存
size_t newLen = strlen(allStrPtr) + (q - (result ? result + strlen(result) : allStrPtr));
result = cast(char*) realloc(result, newLen + 1);
}
// 复制剩余部分
strcpy(result + strlen(result), tempStr);
// 释放临时字符串
free(tempStr);
}
// 将结果转换为字符串
allStr = fromStringz(result).idup;
// 释放内存
if (allStrPtr != result)
{
free(result);
}
return allStr;
}
}
void main()
{
auto start = Clock.currTime();
string str = "hello, world!";
for (int ii = 0; ii < 10000000; ii++)
{
str = str.replaceString('o', '0').replaceString('l', '1').replaceString(',', '').replaceString('!', '');
}
auto end = Clock.currTime();
writeln('D语言程序运行时间 :', end-start);
}
总结
通过以上优化,replaceString 函数的效率得到了显著提升。需要注意的是,strstrCase 函数使用了 strcasestr 函数,该函数在某些平台上可能需要链接 libncurses 库才能正常使用。
希望本文对您有所帮助!
原文地址: https://www.cveoy.top/t/topic/jn9z 著作权归作者所有。请勿转载和采集!