| /*
* Ruslan Teliuk test task.
*/
#include <string.h>
#include <iterator>
#include <iostream>
#include <conio.h>
#include <assert.h>
#if defined(_MSC_VER)
#include <string> //for getline
#endif
namespace helper_functions
{
template<typename T> struct assert_false : public std::false_type {};
template<typename CharType>
size_t string_length(const CharType*) {
static_assert(assert_false<CharType>::value, "Illegal template instantiation sds");
return 0;
}
template<>
size_t string_length<char>(const char *str) { return strlen(str); }
template<>
size_t string_length<wchar_t>(const wchar_t *str) { return wcslen(str); }
}
//..........................................................................................................
class MyClass
{
public: //Core Algorithm's
enum e_predicate_result {
//should return when input is not match to pattern
eNotMatch
//should return when input is separator
, eSeparator
//should return when input is partially match to pattern
, eMatch
//should return when input is full match to pattern
, eFullMatch
};
//..........................................................................................................
template<typename Iter, typename Pred>
static size_t count_of_patterns(Iter begin_, Iter end_, Pred pr_)
{
size_t result = 0;
enum e_state { stWaitForBegin, stMatch, stWaitForMatch, stWaitForEnd };
e_state state = stWaitForMatch;
e_predicate_result cl = eNotMatch;
while(begin_ != end_)
{
cl = pr_(*begin_);
switch(cl)
{
case eNotMatch:
{
state = stWaitForBegin;
} break;
case eMatch:
{
switch(state)
{
case stWaitForEnd:
state = stWaitForBegin;
break;
case stWaitForBegin:
break;
default:
state = stMatch;
}
} break;
case eFullMatch:
{
if(stWaitForBegin != state) {
state = stWaitForEnd;
}
} break;
case eSeparator:
{
switch(state)
{
case stWaitForEnd:
{
result++;
state = stWaitForMatch;
} break;
case stWaitForBegin:
{
state = stWaitForMatch;
} break;
}
} break;
}
begin_++;
}
if(stWaitForEnd == state && eFullMatch == cl) {
++result;
}
return result;
}
//..........................................................................................................
template<typename Iter, typename CIter, typename Pred>
static size_t substitute_pattern(Iter begin_, Iter end_, CIter patt_begin_, CIter patt_end_, CIter repl_begin_, CIter repl_end_, Pred pr_)
{
if(std::distance(patt_begin_, patt_end_) != std::distance(repl_begin_, repl_end_)) return 0;
size_t total_substitutions = 0;
Iter replace_point = end_;
enum e_state { stWaitForBegin, stMatch, stWaitForMatch, stWaitForEnd };
e_state state = stWaitForMatch;
e_predicate_result cl = eNotMatch;
while(begin_ != end_)
{
cl = pr_(*begin_);
switch(cl)
{
case eNotMatch:
{
state = stWaitForBegin;
replace_point = end_;
} break;
case eMatch:
{
switch(state)
{
case stWaitForEnd:
state = stWaitForBegin;
break;
case stWaitForBegin:
break;
default:
state = stMatch;
if(end_ == replace_point) {
replace_point = begin_;
}
}
} break;
case eFullMatch:
{
if(stWaitForBegin != state) {
state = stWaitForEnd;
}
} break;
case eSeparator:
{
switch(state)
{
case stWaitForEnd:
{
state = stWaitForMatch;
CIter it = repl_begin_;
while(repl_end_ != it) {
*replace_point++ = *it++;
}
replace_point = end_;
total_substitutions++;
} break;
case stWaitForBegin:
{
state = stWaitForMatch;
} break;
}
} break;
}
begin_++;
}
if(stWaitForEnd == state && eFullMatch == cl) {
CIter it = repl_begin_;
while(repl_end_ != it) {
*replace_point++ = *it++;
}
++total_substitutions;
}
return total_substitutions;
}
private: //General calls
template<typename CharType>
static size_t getCount(const CharType *str, const CharType *pattern, CharType separator)
{
using namespace helper_functions;
const CharType *pb = pattern, *pe = pattern + string_length(pattern);
return count_of_patterns(str, str+string_length(str), [pattern, &pb, pe, separator](CharType c) -> e_predicate_result
{
if(c == *pb)
{
++pb;
if(pb == pe) {
pb = pattern;
return eFullMatch;
}
return eMatch;
}
pb = pattern;
return separator == c ? eSeparator : eNotMatch;
}
);
}
//..........................................................................................................
template<typename CharType>
static size_t replaceWith(CharType *str, const CharType *from, const CharType *to, CharType separator)
{
using namespace helper_functions;
const CharType *pb = from, *pe = from + string_length(from);
return substitute_pattern(str, str+string_length(str), from, from+string_length(from), to, to+string_length(to), [from, &pb, pe, separator](CharType c) -> e_predicate_result
{
if(c == *pb)
{
++pb;
if(pb == pe) {
pb = from;
return eFullMatch;
}
return eMatch;
}
pb = from;
return separator == c ? eSeparator : eNotMatch;
}
);
}
public: //Calls from test task
static size_t getBmCount(const char *str)
{
return getCount(str, "Bm", ' ');
}
static size_t getBmCount(const wchar_t *str)
{
return getCount(str, L"Bm", L' ');
}
static size_t replaceBmWithBM(char *str)
{
return replaceWith(str, "Bm", "BM", ' ');
}
static size_t replaceBmWithBM(wchar_t *str)
{
return replaceWith(str, L"Bm", L"BM", L' ');
}
};
/*
DESCRIPTION (1. Implement the two functions getBmCount and replaceBmWithBM of the class MyClass):
The core algorithms from the test task implemented in ("Core Algorithm's" section):
template<typename Iter, typename Pred>
static size_t count_of_patterns(Iter begin_, Iter end_, Pred pr_)
and
template<typename Iter, typename CIter, typename Pred>
static size_t substitute_pattern(Iter begin_, Iter end_, CIter patt_begin_, CIter patt_end_, CIter repl_begin_, CIter repl_end_, Pred pr_)
It can be used with raw pointer and with iterators for example std::w/string::iterator.
The predicate function should define the pattern matching and return enum e_predicate_result
It allow a more flexible lookup/replace patterns from the input source even if it should contain the same symbol which is using for separator.
The example functors implementation in "General calls" section:
template<typename CharType>
static size_t getCount(const CharType *str, const CharType *pattern, CharType separator)
and
template<typename CharType>
static size_t replaceWith(CharType *str, const CharType *from, const CharType *to, CharType separator)
*/
int main(int /*argc*/, char** /*argv*/)
{
/*
DESCRIPTION (2. Implement the two functions getBmCount and replaceBmWithBM of the class MyClass):
I replaced the const char/wchar_t * to char/wchar_t[] for allow implace data modifed in replaceXXX functions.
Sorry if I miss misunderstood the test task wrong and replaceXXX functions should return copy of string
If need I can fix it.
*/
char szTestString1[] = "Bm bM BM bM Bm";
wchar_t szTestString2[] = L"Bm bM BM bM Bm";
size_t nBmCountASCII = MyClass::getBmCount(szTestString1);
size_t nBmCountUNICODE = MyClass::getBmCount(szTestString2);
size_t nNumberOfReplacesASCII = MyClass::replaceBmWithBM(szTestString1);
size_t nNumberOfReplacesUNICODE = MyClass::replaceBmWithBM(szTestString2);
/*
DESCRIPTION (3. Display the string given in the last comment on screen. X and Y should be replaced with the real values.):
If I understand correctly the Y it's a input from user.
*/
std::string Y;
getline(std::cin, Y);
std::cout << "Found " << MyClass::getBmCount(Y.c_str()) << " occurrences of Bm. New string: " << Y;
//for pause
getch();
return 0;
}
|