Замените несколько пробелов одним пробелом в строке

Как бы я сделал что-то вроде этого (java) string.replaceAll(" ", " ") в С++

это сделало бы так, чтобы все множественные пробелы становились всего одним.

Ответы

Ответ 1

bool BothAreSpaces(char lhs, char rhs) { return (lhs == rhs) && (lhs == ' '); }

std::string::iterator new_end = std::unique(str.begin(), str.end(), BothAreSpaces);
str.erase(new_end, str.end());   

Как это работает. std::unique имеет две формы. Первая форма проходит через диапазон и удаляет соседние дубликаты. Итак, строка "abbaaabbbb" становится "abab". Вторая форма, которую я использовал, принимает предикат, который должен принимать два элемента и возвращать true, если их следует считать дублирующими. Функция, которую я написал, BothAreSpaces, служит этой цели. Он точно определяет, что означает это имя, что оба параметра - это пробелы. Поэтому в сочетании с std::unique дублируются смежные пространства.

Также как std::remove и remove_if, std::unique фактически не делает контейнер меньшим, он просто перемещает элементы ближе к началу. Он возвращает итератор в новый конец диапазона, поэтому вы можете использовать его для вызова функции erase, которая является функцией-членом функции Строковый класс.

Разбивая его, функция стирания принимает два параметра: начальный и конечный итератор для диапазона для стирания. Для него первый параметр я передает возвращаемое значение std::unique, потому что там, где я хочу начать стирание. Для этого второго параметра я передаю итератор конца строки.

Ответ 2

Итак, я пробовал путь с std:: remove_if и лямбда-выражениями - хотя мне кажется, что мне все еще легче смотреть, чем над кодом, у него нет "ничего себе", не понимал, что вы можете это сделать "вещь к этому.. В любом случае я все равно размещаю его, если только для учебных целей:

bool prev(false);
char rem(' ');
auto iter = std::remove_if(str.begin(), str.end(), [&] (char c) -> bool {
    if (c == rem && prev) {
        return true;
    }
    prev = (c == rem);
    return false;
});
in.erase(iter, in.end());

EDIT понял, что std:: remove_if возвращает итератор, который можно использовать.. удаленный ненужный код.

Ответ 3

Вариант ответа Бенджамина Линдли, который использует выражение лямбда, чтобы сделать вещи чище:

std::string::iterator new_end = 
        std::unique(str.begin(), str.end(),
        [=](char lhs, char rhs){ return (lhs == rhs) && (lhs == ' '); }
        );
str.erase(new_end, str.end());

Ответ 4

Почему бы не использовать регулярное выражение:

boost::regex_replace(str, boost::regex("[' ']{2,}"), " ");

Ответ 5

как насчет isspace(lhs) && isspace(rhs) для обработки всех типов пробелов