目前的规格是:
以宽字符或窄字符数组的形式给定字符串数据,为类提供功能,该类提供数据统计并修改数据。
要求是长期可以维持。
所以我的第一种方法是先将raw char数组编组成字符串,然后只提供一个模板类:
template<class T>
class MyString
{
private:
T _data;
public:
MyString(T& input) { _data = input; };
size_t doSomeWork() { //assume T is of type basic_string<...> and use iterators };
};
//Use
const char* data = "zyx";
string blahblah(data);
MyString<string> abc(blahblah);
abc.doSomeWork();
或静态成员函数:
class StringTools
{
public:
static size_t doWork(const char*) {}
static size_t doWork(const wchar_t*) {}
};
//used like so:
const char* data = "hallo kitty";
cout << StringTools::doWork(data);
或使用策略模式:
class MyString
{
protected:
MyStringBase();
public:
virtual ~MyStringBase();
virtual size_t doWork() = 0;
};
class MyStringCharArray : public MyString
{
protected:
char* _data;
public:
MyStringCharArray(const char* input) : MyString() { }
virtual size_t doWork() {...};
};
//so it would be used like so
const char* blah = "blah";
MyString* str = new MyStringCharArray(blah);
cout << str->doWork();
delete str;
然后在将来如果因为某些上帝遗弃的原因我转而使用BStr,那么除了要编写的新派生类之外,它只需要更改前两行代码。
我认为如果我写一个包装类,如1&amp; 3它变得更加繁重,任何封装都被打破,因为我必须允许访问底层。
但是如果我创建一个只有静态函数的类,那么它所做的就是模仿一个命名空间,这个命名空间可以更好地服务于一个非成员的非友元函数。 “stringtools”命名空间。但是我仍然会在整个应用程序中传播原始字符数组的混乱,并且必须执行额外的验证等规范 明确要求上课。
那么最干净,最易维护的方法是什么?
RGDS
答案 0 :(得分:4)
最好的方法是做类似stl算法的工作。
有一个只接受字符串char / wchart_t开始和结束迭代器的进程算法。这样,您的算法将无缝地用于所有可以在内存中连续的字符串。
答案 1 :(得分:1)
听起来我不喜欢 类,你应该考虑使用完全正常string
/ wstring
数据的通用算法。根据您在统计/修改方面最终需要的内容,您甚至可能不需要编写实际算法,而只需要编写仿函数(例如)std::accumulate
。
如果您最终需要使用类似BSTR的东西,则需要为BSTR提供迭代器接口。但就个人而言,即使我正在处理COM,我几乎一直都会使用普通字符串实际工作,并且在将它传递给某个COM之前立即转换为BSTR。同样在回程中,一旦我收到BSTR,我就将其转换为普通字符串,并以该形式使用它。从理论上讲,如果你和COM一起工作的话,把事情当作BSTR可能会更快,但是我还没有看到转换为正常字符串的转换成任何接近瓶颈的事情。
答案 2 :(得分:0)
这个问题没有明确说明,你正在过度设计这个问题。
将收集哪些统计数据?将对字符串进行哪些更改?这些字符串有多长?性能是否重要?
为什么不使用简单的解决方案:编写所有统计/字符串更改例程以使用UTF-8(假设这是char
s的编码)。如果需要处理UTF-16字符串,请将其转换为UTF-8,调用对其起作用的例程,然后将修改后的字符串转换回UTF-16。 KISS。
编辑:
还有另一个考虑因素:您的算法是否与编码无关(即它是否与字符串的编码无关),即唯一的变量是字符的“宽度”?如果是这种情况,正如parapura所暗示的那样,采用开始和结束迭代器的模板化程序可能是一种选择。
根据您的澄清,听起来好像您的算法目前编码不可知 - 但是既然您提到可维护性,您应该考虑将来是否也会这样做
答案 3 :(得分:0)
好的,所以我已经接受了你们所说的话,我已经将规范中的算法分开了。模仿STL,算法与迭代器一起工作;而规范要求的“MyClass”则封装了领域知识。
这对你们看起来怎么样?
首先关闭算法:
/*
MyLib
---------------
Methods:
countOccurances()
- given the iterator pairs for two either contiguous areas of memory or containers
- counts the number of times the second (needle) occurs in the first (haystack)
- returns the count
replaceOccurances()
- same as countOccurances except when a sequence has been matched it is replaced
by the replacement needle which must be the same length
*/
template<class fwdIt>
size_t countOccurances(fwdIt haystackFront, fwdIt haystackEnd,
fwdIt needleFront, fwdIt needleEnd)
{
size_t lengthOfNeedle = std::distance(needleFront,needleEnd);
size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd);
size_t count = 0;
while(true)
{
//find the needle
fwdIt tempIT1 = haystackFront, tempIT2 = needleFront;
while(true)
{
if(tempIT2 == needleEnd)
{
haystackFront += lengthOfNeedle;
lengthOfHaystack -= lengthOfNeedle;
count++;
break;
}
else if(*tempIT1 != *tempIT2)
{
break;
}
tempIT1++; tempIT2++;
}
if(lengthOfNeedle <= lengthOfHaystack)
{
++haystackFront;
--lengthOfHaystack;
}
else
{
break;
}
}
return count;
}
template<class fwdIt>
size_t replaceOccurances(fwdIt haystackFront, fwdIt haystackEnd,
fwdIt needleFront, fwdIt needleEnd,
fwdIt replacementFront, fwdIt replacementEnd)
{
//The needle and its replacement must be the same length,
//this method cannot be reponsible for growing a container it doesn't own.
if(std::distance(needleFront, needleEnd) != std::distance(replacementFront, replacementEnd))
throw exception("The needle and its replacement are not the same length");
size_t lengthOfNeedle = std::distance(needleFront,needleEnd);
size_t lengthOfHaystack = std::distance(haystackFront,haystackEnd);
size_t count = 0;
while(true)
{
//find the needle
fwdIt tempIT1 = haystackFront, tempIT2 = needleFront;
while(true)
{
if(tempIT2 == needleEnd)
{
//replace the needle
for(fwdIt tempIT3 = replacementFront;
haystackFront != tempIT1, tempIT3 != replacementEnd;
haystackFront++, tempIT3++)
{
*haystackFront = *tempIT3;
}
count++;
break;
}
else if(*tempIT1 != *tempIT2)
{
break;
}
tempIT1++; tempIT2++;
}
if(lengthOfNeedle <= lengthOfHaystack)
{
++haystackFront;
--lengthOfHaystack;
}
else
{
break;
}
}
return count;
}
现在MyClass
class MyClass
{
public:
static size_t getMyCount(std::string& sInput);
static size_t getMyCount(std::wstring& sInput);
static size_t replaceMyWithMY(std::string& sInput);
static size_t replaceMyWithMY(std::wstring& sInput);
protected:
static std::string _narrowNeedle;
static std::wstring _wideNeedle;
static std::string _narrowReplacementNeedle;
static std::wstring _wideReplacementNeedle;
template<class T>
static size_t _PerformStringOperation(T& sInput, T& sNeedle, bool replace = false, T& sReplacementNeedle = T())
{
try
{
if(replace)
{
return replaceOccurances( sInput.begin(), sInput.end(),
sNeedle.begin(), sNeedle.end(),
sReplacementNeedle.begin(), sReplacementNeedle.end());
}
else
{
return countOccurances( sInput.begin(), sInput.end(),
sNeedle.begin(), sNeedle.end());
}
}
catch(MYException& e)
{
clog << "MyClass::_PerformStringOperation() - could not perform operation" << endl;
clog << e.what();
throw;
}
catch(exception& e)
{
clog << "MyClass::_PerformStringOperation() - Something more fundemental went wrong" << endl;
clog << e.what();
throw;
}
}
};
及随附的CPP
std::string MyClass::_narrowNeedle("My");
std::wstring MyClass::_wideNeedle = std::wstring(L"My");
std::string MyClass::_narrowReplacementNeedle = std::string("MY");
std::wstring MyClass::_wideReplacementNeedle = std::wstring(L"MY");
size_t MyClass::getNiCount(std::string& sInput)
{
try
{
return _PerformStringOperation(sInput,_narrowNeedle);
}
catch(...)
{
throw;
}
}
size_t MyClass::getNiCount(std::wstring& sInput)
{
try
{
return _PerformStringOperation(sInput,_wideNeedle);
}
catch(...)
{
throw;
}
}
size_t MyClass::replaceNiWith(std::string& sInput)
{
try
{
return _PerformStringOperation(sInput,_narrowNeedle,true,_narrowReplacementNeedle);
}
catch(...)
{
throw;
}
}
size_t MyClass::replaceNiWith(std::wstring& sInput)
{
try
{
return _PerformStringOperation(sInput,_wideNeedle,true,_wideReplacementNeedle);
}
catch(...)
{
throw;
}
}