/*************************************************************************** * Copyright (C) 2008-2021 by Andrzej Rybczak * * andrzej@rybczak.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef NCMPCPP_REGEX_FILTER_H #define NCMPCPP_REGEX_FILTER_H #include "config.h" #ifdef BOOST_REGEX_ICU # include # include # include #else # include #endif // BOOST_REGEX_ICU #include #include #include "utility/functional.h" namespace { #ifdef BOOST_REGEX_ICU struct StripDiacritics { static void convert(icu::UnicodeString &s) { if (m_converter == nullptr) { icu::ErrorCode result; m_converter = icu::Transliterator::createInstance( "NFD; [:M:] Remove; NFC", UTRANS_FORWARD, result); if (result.isFailure()) throw std::runtime_error( "instantiation of transliterator instance failed with " + std::string(result.errorName())); } m_converter->transliterate(s); } private: static icu::Transliterator *m_converter; }; icu::Transliterator *StripDiacritics::m_converter; #endif // BOOST_REGEX_ICU } namespace Regex { typedef #ifdef BOOST_REGEX_ICU boost::u32regex #else boost::regex #endif // BOOST_REGEX_ICU Regex; template inline Regex make(StringT &&s, boost::regex_constants::syntax_option_type flags) { return #ifdef BOOST_REGEX_ICU boost::make_u32regex #else boost::regex #endif // BOOST_REGEX_ICU (std::forward(s), flags); } template inline bool search(const std::basic_string &s, const Regex &rx, bool ignore_diacritics) { try { #ifdef BOOST_REGEX_ICU if (ignore_diacritics) { auto us = icu::UnicodeString::fromUTF8( icu::StringPiece(convertString::apply(s))); StripDiacritics::convert(us); return boost::u32regex_search(us, rx); } else return boost::u32regex_search(s, rx); #else return boost::regex_search(s, rx); #endif // BOOST_REGEX_ICU } catch (std::out_of_range &e) { // Invalid UTF-8 sequence, ignore the string. std::cerr << "Regex::search: error while processing \"" << s << "\": " << e.what() << "\n"; return false; } } template struct Filter { typedef NC::Menu MenuT; typedef typename NC::Menu::Item Item; typedef std::function FilterFunction; Filter() { } template Filter(const std::string &constraint_, boost::regex_constants::syntax_option_type flags, FilterT &&filter) : m_rx(make(constraint_, flags)) , m_constraint(constraint_) , m_filter(std::forward(filter)) { } void clear() { m_filter = nullptr; } const std::string &constraint() const { return m_constraint; } bool operator()(const Item &item) const { assert(defined()); return m_filter(m_rx, item.value()); } bool defined() const { return m_filter.operator bool(); } private: Regex m_rx; std::string m_constraint; FilterFunction m_filter; }; template struct ItemFilter { typedef NC::Menu MenuT; typedef typename NC::Menu::Item Item; typedef std::function FilterFunction; ItemFilter() { } template ItemFilter(const std::string &constraint_, boost::regex_constants::syntax_option_type flags, FilterT &&filter) : m_rx(make(constraint_, flags)) , m_constraint(constraint_) , m_filter(std::forward(filter)) { } void clear() { m_filter = nullptr; } const std::string &constraint() const { return m_constraint; } bool operator()(const Item &item) { return m_filter(m_rx, item); } bool defined() const { return m_filter.operator bool(); } private: Regex m_rx; std::string m_constraint; FilterFunction m_filter; }; } #endif // NCMPCPP_REGEX_FILTER_H