C++ 如何快速地用另一个字符替换字符串中的一个字符(我认为测试不需要通用方法)
我在技术测试中被问到这个问题。C++ 如何快速地用另一个字符替换字符串中的一个字符(我认为测试不需要通用方法),c++,algorithm,c++11,replace,c-strings,C++,Algorithm,C++11,Replace,C Strings,我在技术测试中被问到这个问题。 他们询问如何将字符串中的“”改为“u”。 我想他们不想要共同的答案。像这样(我可以保证) void replaceChar(char originalStr[],大小strLength,char originalshar,char newChar { 对于(大小i=0;i
他们询问如何将字符串中的“”改为“u”。
我想他们不想要共同的答案。像这样(我可以保证)
void replaceChar(char originalStr[],大小strLength,char originalshar,char newChar
{
对于(大小i=0;i
所以我的回答是这样的。使用WORD。(实际上我没有编写代码,他们只是想解释如何做)我认为将字符串的每个8字节(64位操作系统)与掩码8字节进行比较。
如果它们相等,则一次更换8字节 当Cpu读取大小小于字的数据时,Cpu应执行清除剩余位的操作。
很慢,所以我试着用这个词来比较字符
void replaceChar(char originalStr[], size_t strLength, char originalChar, char newChar //
{
size_t mask = 0;
size_t replaced = 0;
for(size_t i = 0 ; i < sizeof(size_t) ; i++)
{
mask |= originalChar << i;
replaced |= newChar << i;
}
for(size_t i = 0 ; i < strLength ; i++)
{
// if 8 byte data equal with 8 byte data filled with originalChar
// replace 8 byte data with 8 byte data filled with newChar
if(i % sizeof(size_t) == 0 &&
strLength - i > sizeof(size_t) &&
*(size_t*)(originalStr + i) == mask)
{
*(size_t*)(originalStr + i) = replaced;
i += sizeof(size_t);
continue;
}
if(originalStr[i] == originalChar)
{
originalStr[i] = newChar ;
}
}
}
void replaceChar(char originalStr[],大小strLength,char originalshar,char newChar/)
{
尺寸=0;
替换的大小=0;
对于(size\u t i=0;i mask |=originalChar快速发展的第一件事是正确的。原始方案的问题是sizeof(s)
应该是strlen(s)的缓存值
。然后,明显的问题是,这种方法会扫描字符串两次——首先查找终止字符,然后查找要替换的字符
这应该通过具有已知长度的数据结构或数据结构来解决,该数据结构具有足够多的保证多余数据,以便可以一次处理多个字节,而不会出现未定义的行为
一旦这一问题得到解决(OP已被编辑以解决这一问题),建议的扫描8个字节的数据的方法的问题是,对于所有相同的字节,一个通用大小写确实有8个连续字符,但可能只有7个。在所有这些情况下,需要扫描相同的区域两次(在扫描字符串终止字符的顶部)
如果字符串长度未知,最好使用低级方法:
while (*ptr != 0) {
if (*ptr == search_char) {
*ptr = replace_char;
}
++ptr;
}
如果字符串长度已知,最好使用库方法std::replace
,或者它的低级对应方法
for (auto i = 0; i < size; ++i) {
if (str[i] == search_char) {
str[i] = replace_char;
}
}
for(自动i=0;i
任何像样的编译器都能够自动向量化,尽管编译器可能会生成比预期更多种类的内核(一个内核用于小尺寸,一个用于中间,一个用于处理32或64字节的块).当您不知道代码的瓶颈是什么时,不要尝试优化代码。请尝试编写清晰可读的代码
此函数声明和定义
void replaceChar(char originalStr[], size_t strLength, char originalChar, char newChar
{
for(size_t i = 0 ; i < strLength ; i++)
{
if(originalStr[i] == originalChar)
{
originalStr[i] = newChar ;
}
}
}
程序输出为
Hello_C_strings!
至于你的第二个函数,它是不可读的。在for循环体中使用continue
语句很难遵循它的逻辑
由于字符数组不必按size\t
的值对齐,因此函数的速度不如您想象的快
如果您需要一个非常优化的函数,那么您应该直接在汇编程序中编写它。您是否绝对确定他们希望您的代码“更快”,而不是“更可读”或“更正确”?“常见答案”是std::replace
,并且您的两个程序中都有一些错误,至少在sizeof
use方面,提出了一个类似的问题,使用replace和regex都得到了很好的答案-速度不是问题。您不知道sizeof
和以null结尾的字符串是如何工作的。您是否测试了建议的解决方案?此外:显示出任何一个好的编译器都不需要被告知一次使用比单个字符更大的块,而且编译器会比您天真的尝试做得更好,只要在可用的地方使用宽向量寄存器。@SungJinKang您可以在没有SIMD的情况下做到这一点,但今天合理的体系结构中使用的SIMD比inte宽一点ger通用寄存器,因此您通常可以通过使用SIMD确保您的代码是内存,甚至是加载/存储带宽(因此没有其他代码可能更快)。另一方面,在不合理的体系结构上(没有SIMD),甚至可能不值得将内存中的起始点与大于char
的大小对齐以进行访问。两种解决方案都显示出相同的性能???在我的基准测试中,使用strchr的解决方案在没有任何优化选项的情况下看起来要快得多。为什么???…我认为它们的性能相同thing@SungJinKang在某些平台上,实现了strchr功能ted实际上是一条汇编指令。@SungJinKang:显示出同样的性能
谁的主张,以及如何建立?微观基准测试是一门黑色艺术,是一个移动的目标。在没有任何优化选项的情况下看起来要快得多
看起来浪费时间和大脑周期。
#include <iostream>
#include <cstring>
char * replaceChar( char s[], char from, char to )
{
for ( char *p = s; ( p = strchr( p, from ) ) != nullptr; ++p )
{
*p = to;
}
return s;
}
int main()
{
char s[] = "Hello C strings!";
std::cout << replaceChar( s, ' ', '_' ) << '\n';
return 0;
}
Hello_C_strings!