template<typename> struct is_basic_string : std::false_type { };
template<typename... T> struct is_basic_string<std::basic_string<T...>> : std::true_type { };
template <typename T = std::string, typename = typename std::enable_if_t<is_basic_string<T>::value>>
class Tokenizer
{
public:
Tokenizer(const T &src, typename T::value_type const sep, uint32_t vectorReserve = 0, bool keepEmptyStrings = true)
: _input(src.begin(), src.end())
{
_input.emplace_back(typename T::value_type());
if (vectorReserve)
_itt.reserve(vectorReserve);
auto last_pos(_input.begin());
for (auto pos = _input.begin(); pos != _input.end(); ++pos)
{
if (*pos == sep)
{
if (keepEmptyStrings || last_pos != pos)
_itt.emplace_back(&*last_pos);
last_pos = std::next(pos);
*pos = typename T::value_type(); // write delimiter
}
}
if (last_pos != _input.end())
_itt.emplace_back(&*last_pos);
}
Tokenizer(const T &src, const T& seps, uint32_t vectorReserve = 0, bool keepEmptyStrings = true)
: _input(src.begin(), src.end())
{
_input.emplace_back(typename T::value_type());
if (vectorReserve)
_input.reserve(vectorReserve);
auto last_pos(_input.begin());
for (auto pos = _input.begin(); pos != _input.end(); ++pos)
{
if (seps.find_first_of(*pos) != -1)
{
if (keepEmptyStrings || last_pos != pos)
_itt.emplace_back(&*last_pos);
last_pos = std::next(pos);
*pos = typename T::value_type(); // write delimiter
}
}
if (last_pos != _input.end())
_itt.emplace_back(&*last_pos);
}
Tokenizer(const T &src, std::function<bool(typename T::value_type)> functor, uint32_t vectorReserve = 0, bool keepEmptyStrings = true)
: _input(src.begin(), src.end())
{
_input.emplace_back(typename T::value_type());
if (vectorReserve)
_input.reserve(vectorReserve);
auto last_pos(_input.begin());
for (auto pos = _input.begin(); pos != _input.end(); ++pos)
{
if (functor(*pos))
{
if (keepEmptyStrings || last_pos != pos)
_itt.emplace_back(&*last_pos);
last_pos = std::next(pos);
*pos = typename T::value_type(); // write delimiter
}
}
if (last_pos != _input.end())
_itt.emplace_back(&*last_pos);
}
private:
std::vector<typename T::value_type> _input;
std::vector<typename T::value_type*> _itt;
public:
typedef typename std::vector<typename T::value_type*>::size_type size_type;
typedef typename std::vector<typename T::value_type*>::iterator iterator;
typedef typename std::vector<typename T::value_type*>::const_iterator const_iterator;
typedef typename std::vector<typename T::value_type*>::reference reference;
typedef typename std::vector<typename T::value_type*>::const_reference const_reference;
iterator begin() { return _itt.begin(); }
iterator end() { return _itt.end(); }
const_iterator begin() const { return _itt.begin(); }
const_iterator end() const { return _itt.end(); }
size_type size() const { return _itt.size(); }
reference operator [] (size_type i) { return _itt[i]; }
const_reference operator [] (size_type i) const { return _itt[i]; }
};
void ChatTranslate::ReplaceWord(std::wstring& haystack, const std::wstring& needle, const std::wstring& new_needle)
{
//! TODO Clean this mess up
std::wstring::size_type pos(0);
std::wstring matchingCaseNeedle;
matchingCaseNeedle.reserve(new_needle.length());
while ((pos = haystack.find(needle, pos)) != std::wstring::npos)
{
// Replace occurence of the pattern if and only if the pattern match is a full word
if ((pos == 0 || !std::iswalpha(haystack[pos - 1])) && (pos + needle.length() >= haystack.length() || !std::iswalpha(haystack[pos + needle.length()])))
{
// Copy case
//! TODO This is locale dependant starting with MoP (reasons?)
matchingCaseNeedle = new_needle;
for (std::wstring::size_type i = 0; i < std::min(needle.length(), new_needle.length()); ++i)
if (!std::iswlower(haystack.at(pos + i)))
matchingCaseNeedle[i] = std::towlower(matchingCaseNeedle[i]);
haystack.replace(pos, needle.length(), matchingCaseNeedle);
}
pos += new_needle.length(); // Avoid replacing in case new_needle contains needle, resulting in an infinite loop
}
}