对大字符串进行更快的操作

Posted

技术标签:

【中文标题】对大字符串进行更快的操作【英文标题】:Faster operations on a large string 【发布时间】:2013-04-01 08:06:24 【问题描述】:

假设我有一个像这样的大随机字符串......

_W:,aLH#J&A4=IY;    ?RVUc?W+</59JG4WSGW6G6$QEHQ:>,*b60$BYR=D=-^8-4(0    "??YaI0Y    SD9 FJ;MZ,V+'S]0:9L%;#a23cO%bMY[O6^S;ULRV2XA    8&  6_5W21E+Y$RYY$K"Q.0J+:cJC301M3H![7
L%K
Q5(4I9/9DAFR,-8<BJ=4H>9M,OX!.A4aQ:
BK<a"1ID.=U-US`R_])>GG)UL\!G?U$RRG_
HcW 3;<U5`X.?:6K@H*ZD3[M!ZU#KJXbE<Y*VV#ZYU#=]?Q
5:a^]#T

XRT.V]>57#W"U1=K$X]&JIY)::AE :K'7!_DV1B>SJ9D_`]>aC"N'US$;CaHK<N#-
"cJ,%RT)!J0DLFUb[[FOCQX(/.E3#
U
L$("+$) ;TDZ
;T#XS-'6U4`UKZ0a85D&+a]I.C/-7LDM_#/aS9OYA!#^G1II*XKL`;c
ES62Wa^=BQHK6E&A .X+4FDZ:   3UOaJ
#1<BY:;@D:`^`8E\-[9&7PXPH

... a lot more

我想对整个字符串进行操作,比如在分号后插入换行符。

#include <iostream>
#include <cmath>
#include <algorithm>

int main()

    std::string buffer = "";
    std::string line = "";
    while (std::getline(std::cin, line))
        buffer += line + std::string("\n");

    auto it = std::find(buffer.begin(), buffer.end(), ';');
    while (it != buffer.end())
    
        buffer.insert(it, '\n');
        it = std::find(it+1, buffer.end(), ';');
    
    std::cout << buffer << std::endl;
    return 0;

这显然需要很长时间。我该怎么办?如果我将它们分成更小的字符串会更好吗?如果没有,我怎样才能让它更快?

编辑

我是个白痴。我在这行有一个无限循环

- it = std::find(buffer.begin(), buffer.end(), ';');
+ it = std::find(it+1, buffer.end(), ';');

尽管我仍然感谢提供了很好答案的人。

【问题讨论】:

好吧,如果你想在两者之间插入东西,它不会快得多。您可以非常快速地在末尾或前面插入...其余的只是查找/搜索工作,并且文档越大需要更多时间...即使是格式良好的文件/字符串 你以后打算怎么处理这个字符串? 【参考方案1】:

虽然我通常更喜欢使用 C++ 标准库,但在这种特殊情况下,我认为老式 C 风格的代码可能是更好的选择。

如果您要进行的处理取决于一次解释一个字符(例如,在分号后插入换行符),然后一次读入一个字符,然后写出一个(或两个,如果字符是如果输入和输出都被缓冲,分号并且必须后跟一个额外的换行符)将非常快。

如果字符n 的处理仅依赖于字符1n,那么类似的方法将起作用——只需根据看到的字符预先决定处理操作far 或存储所有前面的字符,以便可以根据1n 的所有字符来决定动作。

在这两种情况下,都不需要将字符插入字符串的中间,因此必须移动大块内存。

仅当对字符 n 的处理(例如是否在该字符之后插入一个字符)取决于字符 n 之后的字符时,才需要在处理之前读入所有文本。即使这样,对于所有插入的字符必须移动的内存量也可以减少到不超过N 个字符,其中N 是已处理字符串的总长度(如果需要,还可以添加其他字符) ,通过使用如下函数:

void copyWithProcessing (char *from, char *to) 
    while (*from) 
        // do any pre-processing
        *to++ = *from++;
        // do any post-processing
     
 

这假设我们可以为to 指向的字符数组预先分配足够的空间,因为我们提前知道由于即将发生的处理需要多少额外的字符。或者,如果我们不需要将生成的字符串存储在内存中,我们可以在每个字符的处理完成后逐个字符地写出来,这意味着我们根本不需要为它分配任何空间。

【讨论】:

【参考方案2】:

您不需要为此求助于 C 风格的编程,在 C++ 中,您可以使用 std::ostringstream 作为结果,并在您阅读的每一行中立即插入换行符:

#include <iostream>
#include <string>
#include <sstream>

int main()

    std::ostringstream buffer;
    std::string line;
    while (std::getline(std::cin, line))
    
        auto prev = 0;
        auto pos = line.find(';');
        while (pos != std::string::npos)
        
            ++pos;
            buffer.write(&line[prev],pos-prev);
            buffer.put('\n');
            prev = pos;
            pos = line.find(';',pos);
        
        buffer.write(&line[prev],line.size()-prev);
        buffer.put('\n');
    

    std::cout << buffer.str() << std::endl;
    return 0;
 

【讨论】:

以上是关于对大字符串进行更快的操作的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JSONStream 对大对象进行字符串化

在字符串上生成唯一的整数/长哈希键,以便更快地进行比较

QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度

objectForPrimaryKey 与过滤查询(匹配主键)性能,哪个对大数据更快?

帮你更快认识Vuex,数据流向

是否可以更快地替换Java String中的方法?