Tomek
Tomek

Reputation: 4829

Easy way to shift specific characters in a string in C++?

If I have the string .....ZZ..ZZ..... or .Z.1.Z.23Z.4.Z55,

Is there an easy way of shifting all Zcharacters in the string one space right of the current position?

Some additional test strings are:

I think a few of the higher voted answers to this question (including the currently accepted one) do not work on these tests.

Upvotes: 1

Views: 12631

Answers (3)

John Millikin
John Millikin

Reputation: 200766

Just iterate through the text and swap characters:

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;
}

Produces:

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

There's a lot of discussion in the comments about a possible off-by-1 error in the above code. However, simple testing / stepping through is enough to show that this is not the case.

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

I think the behavior of "dropping" trailing Zs when shifting off the end of the string is sensible. After all, if you shift the bits of an integer, bits that end up outside the bounds of the integer are dropped.

If another behavior is desired -- for example, shifting only within the string -- the change to the algorithm is minimal:

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

Upvotes: 5

ypnos
ypnos

Reputation: 52337

Building on previously posted code here. Function gets str and strlen, overwrites str. Works also with subsequent Z. Going forward for speed improvement with subsequent 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
        }
    }
}

Note that John Millikin's solution is nicer to read and also correct.

Upvotes: 2

Steve Lacey
Steve Lacey

Reputation: 823

Slight fix to the previous answer (shift to the right and assume '.' means "can move here"):

  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';
    }
  }

Upvotes: 0

Related Questions