Простой способ сдвинуть определенные символы в строке в C++?

Если у меня есть строка .....ZZ..ZZ..... или .Z.1.Z.23Z.4.Z55,

Есть ли простой способ сдвинуть все символы Z в строке на один пробел вправо от текущей позиции?

Некоторые дополнительные тестовые строки:

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

Я думаю, что некоторые из наиболее высоко оцененных ответов на этот вопрос (включая принятый в настоящее время) не работают в этих тестах.

Вам нужно дать более точную спецификацию. Когда вы говорите «сдвинуть вправо», вы имеете в виду поменять местами букву «Z» и символ вправо? Сдвинуть его и поставить пробел (или что-то в этом роде) на то место, где оно было? Что делать, если Z - последний символ? Каков правильный результат для ваших тестовых строк?

Michael Burr 21.10.2008 11:40

Также дайте правильный ответ для каждой тестовой строки. Простое указание на них и на то, что данные решения не работают, не очень помогает.

Andreas Magnusson 21.10.2008 18:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
11 569
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Просто перебирайте текст и меняйте местами символы:

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..

В комментариях много говорится о возможной ошибке «off-by-1» в приведенном выше коде. Однако простого тестирования / пошагового выполнения достаточно, чтобы показать, что это не так.

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

Я думаю, что поведение "опускания" конечных Z при смещении с конца струны является разумным. В конце концов, если вы сдвинете биты целого числа, биты, выходящие за пределы целого числа, будут отброшены.

Если желательно другое поведение - например, сдвиг только внутри строки - изменение алгоритма минимально:

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

@Martin: ой, ой, изменится

John Millikin 21.10.2008 09:18

но что, если у вас есть 2 Z рядом друг с другом, или 3 Z, или 4 и т. д., и вы хотите сдвинуть каждую из них?

Tomek 21.10.2008 09:32

@Tomek: Если я не ошибаюсь, мой код делает это. Измените text на "..ZZ .." или что-то еще, и он выдаст правильный результат.

John Millikin 21.10.2008 09:38

@John: Мне жаль, что вы были правы, я проделывал это на бумаге, и это не имело смысла, но потом я увидел, что вы начинаете с правой стороны строки, вот как все это работает. Теперь все лучше, еще раз спасибо

Tomek 21.10.2008 10:09
В этом коде есть ошибка. ii должен начинаться с text_len - 2! в противном случае, если Z - последний символ в строке, он будет заменен завершающим символом '\ 0'.
ypnos 21.10.2008 10:18

Это тоже неправильно, потому что, если оно заканчивается на «Z», то «Z» не будет заменено местами.

1800 INFORMATION 21.10.2008 10:36

Все было так, как я сказал. Автор исправил код своим комментарием. Спасибо.

ypnos 21.10.2008 10:37

Нет, он этого не сделал, я изменил его из-за вашего комментария, а затем вернул обратно. В любом случае это неправильно

1800 INFORMATION 21.10.2008 10:40

@ypnos: ошибки отклонения нет. strlen исключает терминатор NULL.

John Millikin 21.10.2008 11:36

если вы начнете с ii = text_len - 1 и text [text_len-1] (последний символ перед '\ 0'!) == 'Z', то вы замените текст [textlen], который является '\ 0' , поэтому Z будет заменен на строку с завершающим нулем! Это потому что strlen исключает нулевой терминатор.

ypnos 21.10.2008 18:24

Простой тест для выяснения причины - это, конечно, увидеть, что произойдет, если строка, переданная в подпрограмму, будет просто "Z". Конечно, решить, что в таком случае должно произойти, непросто.

Andreas Magnusson 21.10.2008 18:40

Я не уверен, как это должно работать, но простой тест дал мне понять, что использование ypnos fix для этого кода кажется правильным решением, поскольку измененная строка все равно будет перестановкой оригинала. Как сейчас, этого не будет.

Andreas Magnusson 21.10.2008 18:56

Спасибо Андреасу за экспертную оценку. Забавно, что в коде есть явная ошибка, некоторые разработчики смотрят именно на нее и не осознают этого.

ypnos 21.10.2008 20:55

Поскольку вопрос сильно недооценен, трудно спорить, что правильно, а что неправильно, но если вы позволите Z: s сдвинуться «с» строки, вы в конечном итоге примете решение вместо этого заменить что-то другое (что?) Или обрезать строку. Мне ни один из этих двух вариантов не кажется хорошим.

Andreas Magnusson 22.10.2008 12:18

> Если требуется другое поведение [snip], изменение 'text_len - 1' на text_len - 2 'решит эту проблему более аккуратно, чем добавление if (temp == 0) в цикл. Если задуматься, на самом деле эти два значения означают одно и то же.

Andreas Magnusson 22.10.2008 12:21

Незначительное исправление к предыдущему ответу (сдвиньте вправо и предположите, что "." Означает "здесь можно двигаться"):

  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 и т. д., и вы хотите сдвинуть каждую из них?

Tomek 21.10.2008 09:24

Я считаю, что приведенный выше код должен это сделать. Он сместит крайний правый, затем следующий крайний правый и т. д. начиная с: ZZ. Шаги приведут к: ZZ. Z.Z .ZZ

Steve Lacey 21.10.2008 09:44

Основываясь на ранее опубликованном коде здесь. Функция получает 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
        }
    }
}

Обратите внимание, что решение Джона Милликина удобнее читать, а также исправлять.

Другие вопросы по теме