Вы простудились так:
pattern = re.compile(r"menu_item = '(.*?)(?<!\\)'", re.DOTALL)
Он начнет сопоставляться по первой одиночной кавычки, которую он найдет, и заканчивается с первой одиночной цитатой, которой не предшествует обратная косая черта. Он также фиксирует любые новые строки и вкладки, найденные между двумя одинарными кавычками.
РЕДАКТИРОВАНИЕ Начиная с 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 <rim(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;
}
я сохраняю исходный ответ выше хотя для контекста и в интересах хранения высокого проголосовавшего ответа все еще доступным.
Я не уверен, является ли Ваша среда тем же, но в моей, случай пустой строки заставит программу прерываться. Я или обернул бы тот вызов стирания с если (! s.empty ()) или Повышение использования, как уже упомянуто.
В случае пустой строки Ваш код предполагает, что добавление 1 к string::npos
дает 0. string::npos
имеет тип string::size_type
, который не подписан. Таким образом Вы полагаетесь на поведение переполнения дополнения.
Взломанный прочь 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;
}
Это работает на пустой случай также.:-)
Используя строковые алгоритмы Повышения были бы самыми легкими:
#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
, можно обрезать все символы, удовлетворяющие пользовательский предикат, в противоположность просто пробелам.
Используйте следующий код для исправления (запаздывающих) пробелов для обрезки и символов табуляции от 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 );
}
Хорошо этот maight не быть самым быстрым, но это... просто.
str = " aaa ";
int len = str.length();
// rtrim
while(str[len-1] == ' ') { str.erase(--len,1); }
// ltrim
while(str[0] == ' ') { str.erase(0,1); }
Вышеупомянутые методы хороши, но иногда вы хотите использовать комбинацию функций для того, что ваша подпрограмма считает пробелами. В этом случае использование функторов для объединения операций может привести к путанице, поэтому я предпочитаю простой цикл, который я могу изменить для обрезки. Вот немного измененная функция обрезки, скопированная из версии 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);
}
Вот что я придумал:
std::stringstream trimmer;
trimmer << str;
trimmer >> str;
Извлечение потока автоматически удаляет пробельные символы, так что это работает как шарм.
Довольно чисто и элегантно, если так можно выразиться. ;)
Мне нравится решение tzaman, единственная проблема с ним в том, что оно не обрезает строку, содержащую только пробелы.
Чтобы исправить этот недостаток, добавьте str.clear() между двумя обрезающими строками
std::stringstream trimmer;
trimmer << str;
str.clear();
trimmer >> str;
Эта версия обрезает внутренние пробелы и не буквенно-цифровые символы:
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;
}
Вот решение для обрезки с regex
#include <string>
#include <regex>
string trim(string str){
return regex_replace(str, regex("(^[ ]+)|([ ]+$)"),"");
}