Какой лучший способ обрезать std :: string?

Вы простудились так:

pattern = re.compile(r"menu_item = '(.*?)(?<!\\)'", re.DOTALL)

Он начнет сопоставляться по первой одиночной кавычки, которую он найдет, и заканчивается с первой одиночной цитатой, которой не предшествует обратная косая черта. Он также фиксирует любые новые строки и вкладки, найденные между двумя одинарными кавычками.

733
задан Angie Quijano 14 April 2016 в 00:17
поделиться

12 ответов

РЕДАКТИРОВАНИЕ Начиная с C++ 17, некоторые части стандартной библиотеки были удалены. К счастью, начиная с C++ 11, у нас есть лямбды, которые являются отличным решением.

#include <algorithm> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
        return !std::isspace(ch);
    }));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
        return !std::isspace(ch);
    }).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
    trim(s);
    return s;
}

Благодаря https://stackoverflow.com/a/44973498/524503 для перевода в рабочее состояние современного решения.

Исходный ответ:

я склонен использовать один из этих 3 для моих потребностей обрезки:

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start
static inline std::string &ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// trim from end
static inline std::string &rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// trim from both ends
static inline std::string &trim(std::string &s) {
    return ltrim(rtrim(s));
}

Они справедливо сам объяснительные и работают очень хорошо.

РЕДАКТИРОВАНИЕ : BTW, я имею std::ptr_fun там, чтобы помочь снять неоднозначность std::isspace, потому что существует на самом деле второе определение, которое поддерживает локали. Это, возможно, было броском все равно, но я склонен любить это лучше.

РЕДАКТИРОВАНИЕ : обратиться к некоторым комментариям о принятии параметра ссылкой, изменением и возвратом его. Я Соглашаюсь. Реализация, которую я, вероятно, предпочел бы, будет двумя наборами функций, один для на месте и тот, который делает копию. Лучший набор примеров был бы:

#include <algorithm> 
#include <functional> 
#include <cctype>
#include <locale>

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrim_copy(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrim_copy(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trim_copy(std::string s) {
    trim(s);
    return s;
}

я сохраняю исходный ответ выше хотя для контекста и в интересах хранения высокого проголосовавшего ответа все еще доступным.

596
ответ дан jotik 14 April 2016 в 00:17
поделиться

Я не уверен, является ли Ваша среда тем же, но в моей, случай пустой строки заставит программу прерываться. Я или обернул бы тот вызов стирания с если (! s.empty ()) или Повышение использования, как уже упомянуто.

3
ответ дан Steve 14 April 2016 в 00:17
поделиться

В случае пустой строки Ваш код предполагает, что добавление 1 к string::npos дает 0. string::npos имеет тип string::size_type, который не подписан. Таким образом Вы полагаетесь на поведение переполнения дополнения.

15
ответ дан Greg Hewgill 14 April 2016 в 00:17
поделиться

Взломанный прочь Cplusplus.com

std::string choppa(const std::string &t, const std::string &ws)
{
    std::string str = t;
    size_t found;
    found = str.find_last_not_of(ws);
    if (found != std::string::npos)
        str.erase(found+1);
    else
        str.clear();            // str is all whitespace

    return str;
}

Это работает на пустой случай также.:-)

14
ответ дан Jean-François Fabre 14 April 2016 в 00:17
поделиться

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

#include <boost/algorithm/string.hpp>

std::string str("hello world! ");
boost::trim_right(str);

str теперь "hello world!". Существует также trim_left и trim, который обрезает обе стороны.

<час>

, Если Вы добавляете _copy суффикс к какому-либо из вышеупомянутых имен функций, например, trim_copy, функция возвратит обрезанную копию строки вместо того, чтобы изменить его через ссылку.

, Если Вы добавляете _if суффикс к какому-либо из вышеупомянутых имен функций, например, trim_copy_if, можно обрезать все символы, удовлетворяющие пользовательский предикат, в противоположность просто пробелам.

400
ответ дан LogicStuff 14 April 2016 в 00:17
поделиться

Используйте следующий код для исправления (запаздывающих) пробелов для обрезки и символов табуляции от std::strings ( ideone):

// trim trailing spaces
size_t endpos = str.find_last_not_of(" \t");
size_t startpos = str.find_first_not_of(" \t");
if( std::string::npos != endpos )
{
    str = str.substr( 0, endpos+1 );
    str = str.substr( startpos );
}
else {
    str.erase(std::remove(std::begin(str), std::end(str), ' '), std::end(str));
}

И только балансировать вещи, я буду включать левый код для обрезки также ( ideone):

// trim leading spaces
size_t startpos = str.find_first_not_of(" \t");
if( string::npos != startpos )
{
    str = str.substr( startpos );
}
59
ответ дан Bill the Lizard 14 April 2016 в 00:17
поделиться

Хорошо этот maight не быть самым быстрым, но это... просто.

str = "   aaa    ";
int len = str.length();
// rtrim
while(str[len-1] == ' ') { str.erase(--len,1); }
// ltrim
while(str[0] == ' ') { str.erase(0,1); }
2
ответ дан 22 November 2019 в 21:24
поделиться

Вышеупомянутые методы хороши, но иногда вы хотите использовать комбинацию функций для того, что ваша подпрограмма считает пробелами. В этом случае использование функторов для объединения операций может привести к путанице, поэтому я предпочитаю простой цикл, который я могу изменить для обрезки. Вот немного измененная функция обрезки, скопированная из версии C здесь, на SO. В этом примере я обрезаю не буквенно-цифровые символы.

string trim(char const *str)
{
  // Trim leading non-letters
  while(!isalnum(*str)) str++;

  // Trim trailing non-letters
  end = str + strlen(str) - 1;
  while(end > str && !isalnum(*end)) end--;

  return string(str, end+1);
}
2
ответ дан 22 November 2019 в 21:24
поделиться

Вот что я придумал:

std::stringstream trimmer;
trimmer << str;
trimmer >> str;

Извлечение потока автоматически удаляет пробельные символы, так что это работает как шарм.
Довольно чисто и элегантно, если так можно выразиться. ;)

3
ответ дан 22 November 2019 в 21:24
поделиться

Мне нравится решение tzaman, единственная проблема с ним в том, что оно не обрезает строку, содержащую только пробелы.

Чтобы исправить этот недостаток, добавьте str.clear() между двумя обрезающими строками

std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
25
ответ дан 22 November 2019 в 21:24
поделиться

Эта версия обрезает внутренние пробелы и не буквенно-цифровые символы:

static inline std::string &trimAll(std::string &s)
{   
    if(s.size() == 0)
    {
        return s;
    }

    int val = 0;
    for (int cur = 0; cur < s.size(); cur++)
    {
        if(s[cur] != ' ' && std::isalnum(s[cur]))
        {
            s[val] = s[cur];
            val++;
        }
    }
    s.resize(val);
    return s;
}
1
ответ дан 22 November 2019 в 21:24
поделиться

Вот решение для обрезки с regex

#include <string>
#include <regex>

string trim(string str){
    return regex_replace(str, regex("(^[ ]+)|([ ]+$)"),"");
}
0
ответ дан 22 November 2019 в 21:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: