参考自:https://blog.csdn.net/ac540101928/article/details/52786435
上面链接的方法详细讲解了最短编辑距离算法,但不能处理中文字符。
unicode和utf-8互转:https://www.cnblogs.com/cthon/p/9297232.html
#include "EditDistance.h"
#include <string>
using std::cout;
using std::endl;
using std::string;
//判断字符的字节长,以便区分编码规则,实现utf-8编码
/// 获取一个字节高位开头为1的个数
size_t nBytesCode(const char ch)
{
if(ch & (1 << 7))//如果ch是多字节的,下面循环,判断utf-8编码的字节长
{
int nBytes = 1;
for(int idx = 0; idx != 6; ++idx)
{
if(ch & (1 << (6 - idx)))
{
++nBytes;
}
else
break;
}
return nBytes;//返回字节长
}
return 1;
}
#if 0
//该算法复杂了,不够简洁
size_t nBytesCode(const char ch)
{
size_t nBytes = 0;
if(ch &(1 << 7))
{//对中文进行处理-utf8编码
if((ch & 0xF0) == 0xC0 || (ch & 0xF0) == 0xD0) // 1111 0000
{ // &11xx xxxx
nBytes += 2; // 1100 0000
} // 1101 0000
else if((ch & 0xF0) == 0xE0)
{
nBytes += 3;
}
else if((ch & 0xFF) == 0xF0 ||
(ch & 0xFF) == 0xF1 ||
(ch & 0xFF) == 0xF2 ||
(ch & 0xFF) == 0xF3 ||
(ch & 0xFF) == 0xF4 ||
(ch & 0xFF) == 0xF5 ||
(ch & 0xFF) == 0xF6 ||
(ch & 0xFF) == 0xF7 )
{
nBytes += 4;
}
else if((ch & 0xFF) == 0xF8 ||
(ch & 0xFF) == 0xF9 ||
(ch & 0xFF) == 0xFA ||
(ch & 0xFF) == 0xFB)
{
nBytes += 5;
}
else if((ch & 0xFF) == 0xFC)
{
nBytes += 6;
}
}
else
{//1字节编码或英文
nBytes += 1;
}
return nBytes;
}
#endif
std::size_t length(const std::string &str)
{
std::size_t ilen = 0;
for(std::size_t idx = 0; idx != str.size(); ++idx)
{
int nBytes = nBytesCode(str[idx]);
idx += (nBytes - 1);
++ilen;
}
return ilen;
}
int triple_min(const int &a, const int &b, const int &c)
{
return a < b ? (a < c ? a : c) : (b < c ? b : c);
}
int editDistance(const std::string & lhs, const std::string &rhs)
{//计算最小编辑距离-包括处理中英文
size_t lhs_len = length(lhs);//字符长
size_t rhs_len = length(rhs);
size_t blhs_len = length(lhs);//字节长
size_t brhs_len = length(rhs);
int editDist[lhs_len + 1][rhs_len + 1];
for(size_t idx = 0; idx <= lhs_len; ++idx)
{
editDist[idx][0] = idx;
}
for(size_t idx = 0; idx <= rhs_len; ++idx)
{
editDist[0][idx] = idx;
}
std::string sublhs, subrhs;
for(std::size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len && lhs_idx <= blhs_len; ++dist_i, ++lhs_idx)//lhs_idx<=blhs_len一定要加上,防止substr处理越界,自己调试几下就清楚了
{
size_t nBytes = nBytesCode(lhs[lhs_idx]);
sublhs = lhs.substr(lhs_idx, nBytes);
lhs_idx += (nBytes - 1);
for(std::size_t dist_j = 1, rhs_idx = 0; dist_j <= rhs_len && rhs_idx <= brhs_len; ++dist_j, ++rhs_idx)
{
nBytes = nBytesCode(rhs[rhs_idx]);
subrhs = rhs.substr(rhs_idx, nBytes);
rhs_idx += (nBytes - 1);
if(sublhs == subrhs)
{
editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j - 1];
}
else
{
editDist[dist_i][dist_j] = triple_min(
editDist[dist_i][dist_j - 1] + 1,
editDist[dist_i - 1][dist_j] + 1,
editDist[dist_i - 1][dist_j - 1] + 1);
}
}
}
return editDist[lhs_len][rhs_len];
}