用单个出现的字符替换连续的重复字符

问题描述 投票:0回答:2

我正在读取 URL(字符串)并搜索模式(连续出现

/
字符)。如果我找到匹配的模式,我想将其替换为单个
/
并按原样复制其余字符。例如:如果输入字符串是
http://www.yahoo.com/
,我需要通过删除额外的
http:/www.yahoo.com/
来生成输出
/
,因为该字符连续出现两次。

这是程序:

int main() {
    int i, j;
    bool found = false;
    unsigned char *str = "http://www.yahoo.com/";
    int len = strlen(str);
    for (i = 0; i < len - 1; i++) {
        if ((str[i] == '/') && (str[i + 1] == '/')) {
            found = true;
            break;
        }
    }
    if (found) {
        for (j = i + 1; j <= (len - i - 2); j++) {
            str[j] = str[j + 1];
        }
    }
    return 0;
}

但是这个程序正在生成分段错误。这段代码的问题出在哪里?知道如何修复它吗?有替代的简单实现吗?

c++ c for-loop duplicates string-literals
2个回答
2
投票

您不得更改字符串文字。它们在 C 和 C++ 中是不可修改的。根据 C 标准(6.4.5 字符串文字)

7 未指定这些数组是否不同,只要它们的 元素具有适当的值。 如果程序尝试 修改这样的数组,行为是未定义的。

使用标准 C 函数

strstr()
memmove()
可以轻松完成该任务。例如

char s[] = "http://www.yahoo.com/";

puts(s);

char *p = strstr(s, "//");

if (p) memmove(p, p + 1, strlen(s) - (p - s));

puts(s);

代码片段的输出将如下所示

http://www.yahoo.com/
http:/www.yahoo.com/

对于你的程序来说,除了尝试更改字符串文字之外,这个循环是错误的

    if (found) {
        for(j = i + 1; j <= (len - i - 2); j++) {
            str[j] = str[j + 1];
        }
    }

它至少应该看起来像

    if (found) {
        for(j = i + 1; j < len; j++) {
            str[j] = str[j + 1];
        }
    }

1
投票

您正在操作字符串文字,它是只读存储器。当您尝试修改字符时,会出现错误。

将字符串数据复制到可写内存中,然后就可以修改它了。

最简单的改变就是做这行:

unsigned char *str = "http://www.yahoo.com/";

改为这样:

char str[] = "http://www.yahoo.com/";

但是,对于 C++,您应该使用

std::string
来代替,然后您可以使用标准搜索算法,如下所示:

#include <string>

int main() {
    std::string str = "http://www.yahoo.com/";
    std::string::size_type i = 0;
    do {
        i = str.find("//", i);
        if (i == std::string::npos) break;
        str.erase(i, 1);      
    }
    while (!str.empty());
    return 0;
}

或者:

#include <string>
#include <algorithm>

bool isBackslashPair(const char c1, const char c2) {
    return ((c1 == '/') && (c2 == '/'));
}

int main() {
    std::string str = "http://www.yahoo.com/";
    std::string::iterator iter = str.begin();
    do {
        iter = std::adjacent_find(iter, str.end(), isBackslashPair);
        if (iter == std::string::end()) break;
        iter = str.erase(iter);      
    }
    while (!str.empty());
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.