【问题标题】:Easy way to shift specific characters in a string in C++?在 C++ 中移动字符串中特定字符的简单方法?
【发布时间】:2008-10-21 05:09:11
【问题描述】:

如果我有字符串.....ZZ..ZZ......Z.1.Z.23Z.4.Z55

有没有一种简单的方法可以将字符串中的所有Zcharacters 移动到当前位置右侧一个空格?

一些额外的测试字符串是:

  • .Z
  • Z.
  • ZZ.
  • .ZZ
  • Z
  • ZZ
  • ZZZ

我认为这个问题的一些较高投票的答案(包括当前接受的答案)不适用于这些测试。

【问题讨论】:

  • 你需要给出一个更好的规范。当您说“向右移动”时,您的意思是将“Z”和字符向右交换吗?移动它并在它所在的位置放置一个空间(或其他东西)?如果“Z”是最后一个字符怎么办?您的测试字符串的正确输出是什么?
  • 请同时给出每个测试字符串的正确答案。简单地陈述它们并且给定的解决方案不起作用并没有多大帮助。

标签: c++ string character


【解决方案1】:

只需遍历文本并交换字符:

int main ()
{
    char text[] = "...Z.Z.Z...", temp;
    int text_len = strlen (text), i;
    for (i = text_len - 1; i >= 0; i--)
    {
        if (text[i] == 'Z')
        {
                temp = text[i+1];
                text[i+1] = text[i];
                text[i] = temp;
        }
    }
    printf ("%s\n", text);
    return 0;
}

生产:

[~]$ gcc zshift.c && ./a.out
....Z.Z.Z..

cmets 中有很多关于上述代码中可能出现的 off-by-1 错误的讨论。然而,简单的测试/单步执行就足以表明情况并非如此。

zshift "Z." -> ".Z"
zshift ".Z" -> "."
zshift "Z" -> ""

我认为当从字符串的末端移开时“掉落”尾随 Zs 的行为是明智的。毕竟,如果你移动一个整数的位,最终超出整数范围的位会被丢弃。

如果需要另一种行为——例如,仅在字符串内移动——对算法的更改是最小的:

temp = text[i+1];
if (temp == 0) continue;
text[i+1] = text[i];
text[i] = temp;

【讨论】:

  • @Martin: 哦,哎呀,会变的
  • 但是,如果您有 2 个 Z 并排,或者 3 个 Z 或 4 个等,并且您想移动它们中的每一个,该怎么办?
  • @Tomek:除非我有误解,否则我的代码就是这样做的。将text 更改为“..ZZ..”之类的,它会输出正确的结果。
  • @John:很抱歉你是对的,我是在纸上逐步完成的,这没有意义,但后来我看到你是从字符串的右侧开始的,这这就是整个事情的运作方式。现在好多了,再次感谢
  • 这段代码有一个bug。 ii需要以text_len - 2开头!否则,如果 Z 是字符串中的最后一个字符,它将与结尾的 '\0' 字符交换。
【解决方案2】:

以之前发布的代码为基础。函数获取 str 和 strlen,覆盖 str。也适用于后续 Z。继续使用后续 Z 提高速度。

void move_z_right (char* str, int strlen) {
    for (unsigned int i = 0; i < strlen - 1; ++i)
    {
        if (str[i] == 'Z')
        {
            unsigned int j = i+1;
            while (str[j] == 'Z' && j < strlen - 1) ++j;
            if (j == strlen) break; // we are at the end, done
            char tmp = str[j];
            str[j] = str[i];
            str[i] = tmp;
            i = j; // continue after new Z next run
        }
    }
}

请注意,John Millikin 的解决方案更易于阅读且更正确。

【讨论】:

    【解决方案3】:

    稍微修正上一个答案(向右移动并假设“。”表示“可以移动到这里”):

      char text[] = "...Z.Z.Z...";
    
      for (int i = strlen(text) - 2); i > 0; --i) {
        if (text[i] == 'Z' && text[i + 1] == '.') {
          text[i] = '.';
          text[i + 1] = 'Z';
        }
      }
    

    【讨论】:

    • 但是如果您有 2 个 Z 并排,或者 3 个 Z 或 4 个等,并且您想移动它们中的每一个,该怎么办?
    • 我相信上面的代码应该可以做到。它会移动最右边的一个,然后是下一个最右边的,等等。例如开头:ZZ。步骤将导致:ZZ。 Z.Z.ZZ
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2022-11-20
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    相关资源
    最近更新 更多