Убрать лишние пробелы и табы в std::string строке

313
11 февраля 2017, 07:49

Допустим есть строка с именем процессора, которую возвращает функция GetProcessorName():

// "Intel<R> Core<TM>2 Duo  CPU    P8400  @ 2.26GHz"
std::string some_string = GetProcessorName();

Необходимо убрать лишние пробелы. То есть, отформатировать строку так, чтобы между словами не было лишних пробелов или знаков табуляции. Вот так:

// "Intel<R> Core<TM>2 Duo CPU P8400 @ 2.26GHz";

Пробовал replace & replace_if, в конце-концов понял, что эти и подобные им алгоритмы предназначены исключительно для контейнеров. Возможно лямбды помогут. Что посоветуете делать с std::string?

Answer 1

вообще то std::string - это обычный контейнер. такой же, как обычный std::vector.

Если не хочется remove/remove_if и душа требует лямбд, можно так

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main() {
    std::string some_string = "Intel<R> Core<TM>2 Duo  CPU    P8400  @ 2.26GHz";
    auto end = std::unique(some_string.begin(), some_string.end(), [](char l, char r){
        return std::isspace(l) && std::isspace(r) && l == r;
    });
    std::cout << std::string(some_string.begin(), end) << '\n';
    return 0;
}

UPD

Некоторые предлагают переписать условие

std::isspace(l) && std::isspace(r) && l == r

как

std::isspace(l) && l == r

я бы его все таки переписал как

std::isspace(l) && std::isspace(r)

Почему? В вопросе звучит "удалить лишние пробелы и табы". А если строка такая (символ подчеркивания - это пробел, а \t - табуляция)

a\t\t__\t_\tb

то ее наверно правильно было бы сократить до a_b, а не a\t_\t_\tb.

Но если посмотреть, что именно проверяет std::isspace, то узнаете, что перевод строки (\n) также считается. Поэтому, если строка будет многострочной вида abc_\n_def, то она будет сокращена до abc_def, что может быть не совсем то, что хочется. Кстати, это вариант ближе к варианту с регуляркой в ответе @GreenDragon, так как \s работает как isspace.

Answer 2

Ну а чем string не контейнер? :)
Сами убедитесь:

int main(int argc, const char * argv[])
{
    string s = "Intel<R>               Core<TM>2 Duo  CPU    P8400  @ 2.26GHz";
    s = s.substr(0,distance(s.begin(),remove_if(s.begin(), s.end(),
                 [](const char& a) { return (a == ' ') && (*(&a+1) == ' '); })));
    cout << "[" << s << "]\n";
}
Answer 3

Немного упрощенный вариант кода @KoVadim под c++03:

#include <iostream>
#include <algorithm>
#include <string>
#include <cctype>
bool space2(char l, char r) {
    return l == r && std::isspace(l);
}
int main() {
    std::string s = "Intel<R> Core<TM>2 Duo  CPU    P8400  @ 2.26GHz";
    std::cout << std::string(s.begin(), std::unique(s.begin(), s.end(), space2)) << '\n';
}
Answer 4

Для работы с текстом можно использовать регулярные выражения. Начиная с C++11 в стандартной библиотеке появилась их поддержка, поэтому вашу задачу также можно решить следующим способом:

#include <iostream>
#include <string>
#include <regex>
int main()
{
  std::string str= "Intel<R> Core<TM>2 Duo  CPU    P8400  @ 2.26GHz";
  std::regex e("(\\s)+");
  std::cout << std::regex_replace (str,e,"$1")<<"\n";
} 
READ ALSO
Окно на передний план (WIN 10)

Окно на передний план (WIN 10)

Есть два приложения которые работают параллельно (условно 1 и 2)Приложение 2 написано на С++(Qt)

532
Запись данных в свойство класса

Запись данных в свойство класса

Есть конструктор, который принимает строку-число, цифры которого записывает в массив numberПри выводе данного массива получаю почему-то рандомные...

319
Использование boost::bind() и shared_from_this()

Использование boost::bind() и shared_from_this()

В примере асинхронного tcp-сервера на бусте связывается функция (все это происходит в классе, наследующим enable_shared_from_this):

358
алгоритм std::move

алгоритм std::move

Испортит ли эта инструкция данные в файле?

299