【问题标题】:Replacing all spaces in a string with '%20' (C++)用 '%20' 替换字符串中的所有空格 (C++)
【发布时间】:2016-07-13 22:36:24
【问题描述】:

难以理解部分代码;我得到的输出也是错误的。问题是用 '%20' 替换字符串中的所有空格。完整代码如下所示;它可以编译,但不能完全按应有的方式运行。

#include <iostream>
#include <string>
using namespace std;

void replaceSpaces(string str){

    //Getting the length of the string, counting the number of spaces 
    int strLen = str.length();
    int i, count = 0;
    for (i = 0; i <= strLen; i++) {
        if(str[i]==' ')
        count++;
    }

    //Determining the new length needed to allocate for replacement characters '%20'
    int newLength = strLen + count * 2;

    str[newLength] = '\0';
    for (i = strLen - 1; i >= 0; i--) {
        if (str[i] == ' ') {
            str[newLength - 1] = '0';
            str[newLength - 2] = '2';
            str[newLength - 3] = '%';
            newLength = newLength - 3;
        }

        else {
            str[newLength - 1] = str[i];
            newLength = newLength -1;
        }
    }
    cout << str <<endl;

}

int main() {

    string str = "hello jellybean hello";
    replaceSpaces(str);

    return 0;

}

我可能遗漏了一些明显的东西,但是当在这一行中分配新的字符串长度时:

int newLength = strLen + count * 2;

这里我们将空格数乘以 2,但如果我们试图用 '%20' 替换所有空格,为什么不乘以 3?


str[newLength] = '\0';

这行是否表示字符串中最后一个字符之后的位置被分配了一个空空格?


我也对else 声明感到困惑。

 else {
        str[newLength - 1] = str[i];
        newLength = newLength -1;
    }

不确定我是否完全了解执行此操作的情况。


函数编译运行时,如果

string str = "hello jellybean hello";

预期的输出将是 hello%20jellybean%20hello,但我得到的输出是 hello%20jellybean%20h

在时间复杂度上,既然有两个独立的for循环,那么时间复杂度会是O(n)吗?

我知道我问了很多不同的问题,非常感谢您的任何回答!

【问题讨论】:

  • 索引(和设置)字符串中的任意位置不会自动将字符串增长到该长度。在那之后,我停止了寻找。哦,好吧,我确实读过关于* 3 的问题。对于每个替换,您减去一个字符 - 原始空间 - 并添加 3。因此 ...
  • str[newLength] 将访问超出为str 分配的内存空间的内存位置。您要做的是创建一个具有新大小的全新字符串,复制旧字符串,同时用“%20”替换空格
  • 最简单的方法是使用strtok() 标记您的字符串(在空格处分割并创建字符串标记)。然后,只需遍历标记并在每个标记之间放置一个 %20...char *tokens = strtok(my_string, " "); while(tokens) { cout &lt;&lt; token &lt;&lt; "%20"; tokens = strtok(NULL, " "); }
  • 谷歌“c++ urlencode”。
  • @Ingenioushax - strtok 不适用于 std::string。而且它很少是正确的答案。

标签: c++ string memory-management str-replace


【解决方案1】:

这是错误的:

str[newLength] = '\0';

std::string 对象根据其大小在内部维护其 NUL 终止符。你想要的

str.resize(newLength);

改为。

【讨论】:

  • 我在str[newLength] = '\0';这行之前添加了str.resize(newLength);行。据我了解,str.resize 将分配新的字符串长度,但是当我尝试执行它时,输出非常混乱。您能否就此提供更多见解?
  • @jellyxbean,正如 Chris 已经提到的,str[newLenght] 是错误的。我在回答中也提到了这一点,你不接受,这当然可以,但我觉得你只是跳到这个答案没有理解它。
  • @gsamaras 我实际上是使用 str.resize() 函数想出来的,这就是为什么我最终接受了这个答案!现在说得通了;我正在为大小为新长度的字符串分配空间,然后将最后一个索引设置为 '\0'。
  • @jellyxbean 但正如 Chris 正确所说,std::string 对象在内部维护 NULL 终止符。我不明白你的意思,但无论如何,评论部分不是用来聊天的。如果您发现解决方案很好。如果没有,请发布一个新问题(如果愿意,请分享链接)。
【解决方案2】:
int newLength = strLen + count * 2;

说分配空间(稍后),等于字符串的长度,加上找到的空格数乘以2,这是有道理的。

例如:so glad to help,应该为% 使用空格所在的插槽,并且每个插槽都需要两个以上的插槽,用于将起作用的替换的20 部分。


这是错误

str[newLength] = '\0';

你看不见吗?您可以访问超出字符串范围的内存。你表现得好像你实际上分配了等于 newLength 的空间,但你还没有在代码中的任何地方这样做。

越界访问会导致未定义行为,这很糟糕。


else 语句仅用于复制非空白字符,但您应该已经放弃该代码(如果它不是您的)并从头开始或/并在以下位置偷偷摸摸:Encode/Decode URLs in C++


至于错误的结果,你应该知道通过到达那个答案的那个点,这是预期的。

【讨论】:

  • 这突然就点了,之前没看懂,感觉挺傻的,谢谢!
  • 别当@jellyxbean,每个人都经历过这样的事情!很高兴我帮了忙! :)
  • @jellyxbean,有什么理由不接受我的回答吗? :)
【解决方案3】:

尝试就地进行修改是很棘手的。创建新字符串要容易得多:

std::string new_string;
for (int i = 0; i < str.length(); ++i) {
    if (str[i] == ' ')
        new_string += "%20";
    else
        new_string += str[i];
}
return new_string;

或者,如果你喜欢 range-for:

std::string new_string;
for (char ch : str) {
    if (ch == ' ')
        new_string += "%20";
    else
        new_string += ch;
}
return new_string;

【讨论】:

    【解决方案4】:

    你可以将函数中的字符串参数改为引用,那么就不需要新的字符串了,在代码的其他部分,你可以使用插入函数添加'2'和'0',你只需要将空格转换为 '&'。

    void replaceSpaces(string &str) {
            size_t strLen = str.length();
            for (int i = 0; i < strLen; i++) {
                if (str[i] == ' ') {
                    str[i] = '%';
                    str.insert(str.begin() + i + 1, '2');
                    str.insert(str.begin() + i + 2, '0');
                    strLen += 2;
                }
            }
        }
    

    【讨论】:

    • 就地修改效率非常低。每次调用insert() 都必须复制字符串中的所有剩余字符,因此这是O(m*n),其中m 是空格数,n 是字符串的大小。
    【解决方案5】:

    这很容易;将examplestring 替换为代码中的字符串,然后照常使用:

    #include <iostream> //debug output
    #include <string>
    
    using std::string;
    using std::cout;
    using std::endl;
    
    //the string to convert
    string examplestring = "this is the example string for spaces into %20";
    
    int main()
    {
        int countspaces = 0; //its faster to fill a known size
        for (auto &x : examplestring)if (x == ' ')countspaces++; //counts spaces
    
        string newstring; //declare new string
        newstring.resize(examplestring.size() + (countspaces*3)); //pre-set size to make it run faster
    
        int newstringiterator = 0; //keep track of new string location
    
        //if ' '(space), place %20 in newstring and add 3 to iteration
        //else just place the letter and iterate
    
        for (int i=0;i<examplestring.size();i++)
        {
            if (examplestring[i] == ' ') 
            { 
                newstring.insert(newstringiterator, "%20");
                newstringiterator += 3;
            }
            else newstring[newstringiterator++] = examplestring[i];
        }
    
      //final newstring is the original with %20 instead of spaces. 
      cout << newstring << endl;
    
      system("PAUSE"); //to read console output
      return 0; //return to zero
    }
    

    这将输出newstring,这是带有“%20”而不是空格的旧字符串。

    【讨论】:

      猜你喜欢
      • 2015-02-13
      • 2012-04-17
      • 2012-01-31
      • 2010-12-03
      • 1970-01-01
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2011-04-17
      相关资源
      最近更新 更多