一个好用的编码类

来源:互联网 发布:js高德地图轨迹清除 编辑:程序博客网 时间:2024/05/01 01:05

本文VC6.0工程源码下载地址:

http://code.google.com/p/serial-num/downloads/detail?name=SerialClass.rar&can=2&q=

 

        大家好,我目前就职于一家工业制造公司,在工作中经常会碰到打印(激光标刻)序列号或流水号的问题,序列号就是某一数值对应的字符串编码,其具有计数功能。

举个例子,客户需要在一批工件上标刻序列号,每个序列号需要用5个字符标刻,即在第一个工件上标刻“00001”,在第二个工件上标刻“00002”,在第三个工件上标刻“00003”,后面的工件依次类推。

 

        起初,碰到这样的问题时,我都会用一个整型变量和一个字符串变量来满足客户的需求,整型变量用来计数,加工的时候就将整型变量转换成字符串变量,然后标刻,每加工完成一个工件后,整型变量自增就可以了。以下是对应的代码片段:

  

const int WIDTH = 5;int nCount = 0;CString strCount;strCount.Format(_T("%0*d"), WIDTH, nCount++);

  

上面的设计思路视乎已能很好的满足客户需求了,但再想一下,要是客户的需求做了如下几种改动时,上面的设计思路是否还能满足客户的需求呢?!

1、客户要用30个字符标刻流水号,在这种情况下,流水号的最大数值已经超过了一个整型变量所能表达的范围。显然上面的代码已不能再满足客户的需求了。

2、客户要用大写英文字母标刻流水号,且除去易混淆的字符QIO等,即23进制编码流水号,且每个流水号仍然用10个字符表示。显然在这种情况下,上面的代码也没法满足客户的需求了。

  

系统自带的数值型变量已经不能再满足个别客户的需求了,那么我们能不能自定义一个变量类型呢,若其具有以下这样一些基本属性,和一些好用的接口,那么我们是不是也能满足客户的个性流水号了呢?

1、能设置每个流水号的宽度。

2、能设置编码符号。

3、将当前编码转换成字符串变量。

4、能与整型变量进行加减运算。(为了获取下一工件的编码)

  

在日常生活中我们手工记流水号时,在脑海中始终是有一个数值的,即现在是第几个工件了,然后再经过思考心算,以10进制、0123456789作为编码符,最后用笔在纸上画下一串符号。但如果让我们在手工记流水号的时候,以23进制、A-Z除去QIO作为编码符记录时,对我们来说,是不是就有困难了呢,特别是对记性不好的人来说(因为要知道n的编码符是个什么形状),但是我们仍然是可以完成的。只不过是,对记忆和运算能力的要求,比记普通流水号的要求要高些。

第一写博客啊,写作能力有限,不知道上面一段话大家能不能看明白,多包涵!

  

模拟我们的日常思维,我们就开始设计自定义变量类型吧!暂先命名为CSerialNum

1、为了CSerialNum类的设计方便,我们先设计这样一个CRightIndexString类,其继承自CString类。

CRightIndexString声明如下:

class CRightIndexString : public CString  {public:CRightIndexString();virtual ~CRightIndexString();public://改写了CString的这个函数void SetAt(int nIndex, TCHAR ch);//改写了CString的这个函数TCHAR operator[](int nIndex) const;//ref-counted copy from another CStringconst CString& operator=(const CString& stringSrc);};

 

 

CRightIndexString实现如下:

CRightIndexString::CRightIndexString(){}CRightIndexString::~CRightIndexString(){}TCHAR CRightIndexString::operator[](int nIndex) const{ASSERT(nIndex>=0 && nIndex<GetLength());return CString::operator[](GetLength()-nIndex-1);}void CRightIndexString::SetAt(int nIndex, TCHAR ch){ASSERT(nIndex>=0 && nIndex<GetLength());CString::SetAt(GetLength()-nIndex-1, ch);}const CString& CRightIndexString::operator=(const CString& stringSrc){return CString::operator=(stringSrc);}

  

        设计CRightIndexString类的主要目的是为了重载CStringoperator[](int nIndex) SetAt(int nIndex, TCHAR ch),重载后,我们能更方便的像日常思维那样计数,即低位在后面,高位在前面。

  

2、下面是CSerialNum类的声明与实现:

CSerialNum类的声明:

CSerialNum::CSerialNum(int nSerialWidth, CString strCodeCharacter, CString strMinValue, CString strMaxValue){//判断有没有重复的编码符for (int n=0; n<strCodeCharacter.GetLength(); n++){if (strCodeCharacter.Find(strCodeCharacter[n]) != strCodeCharacter.ReverseFind(strCodeCharacter[n])){AfxMessageBox(_T("严重错误,编码符中存在重复的字符,请检查!"));return;}}//判断宽度和编码长度的有效性if (0>=nSerialWidth || 0>=strCodeCharacter.GetLength()){AfxMessageBox(_T("构造字符串时,宽度不能是0,且编码字符串不能为空!"));return;}//赋值给成员变量m_nSerialWidth = nSerialWidth;m_strCodeCharacter = strCodeCharacter;//设置序列号的编码范围SetRange(strMinValue, strMaxValue);//将当前序列号设为最小编码串CSerialNum::operator =(strMinValue);}CSerialNum::~CSerialNum(){}BOOL CSerialNum::PaddingStr(CString &str){#ifdef _DEBUGif (m_nSerialWidth < str.GetLength()){AfxMessageBox(_T("严重错误,序列号过长,无法前端补齐!"));return FALSE;}#endifwhile (m_nSerialWidth > str.GetLength()){str = m_strCodeCharacter[0] + str;}return TRUE;}int CSerialNum::CompSerialNum(CString str1, CString str2){PaddingStr(str1);PaddingStr(str2);int nIndex1, nIndex2;for (int n=0; n<str1.GetLength(); n++){nIndex1 = m_strCodeCharacter.Find(str1[n]);nIndex2 = m_strCodeCharacter.Find(str2[n]);if (nIndex1 > nIndex2){return 1;}else if (nIndex2 > nIndex1){return -1;}}return 0;}TCHAR CSerialNum::GetNextCode(TCHAR CrtCode, BOOL OUT &bCarry){int nCrtPosition = m_strCodeCharacter.Find(CrtCode);ASSERT(-1!=nCrtPosition);int nNextPosition = (nCrtPosition+1)%m_strCodeCharacter.GetLength();bCarry = (0==nNextPosition) ? TRUE : FALSE;return m_strCodeCharacter[nNextPosition];}BOOL CSerialNum::SetRange(CString strMinValue, CString strMaxValue){if (m_nSerialWidth < strMinValue.GetLength() || m_nSerialWidth < strMaxValue.GetLength()){AfxMessageBox(_T("设置序列号范围时,字符串过长,请检查!"));return FALSE;}if (0 >= strMinValue.GetLength() || 0 >= strMaxValue.GetLength()){AfxMessageBox(_T("设置序列号范围时,字符串过短,请检查!"));return FALSE;}if (strMinValue != strMinValue.SpanIncluding(m_strCodeCharacter) || strMaxValue != strMaxValue.SpanIncluding(m_strCodeCharacter)){AfxMessageBox(_T("设置序列号范围时,字符串含有未识别字符,请检查!"));return FALSE;}if (1 == CompSerialNum(strMinValue, strMaxValue)){AfxMessageBox(_T("设置序列号范围时,最小编码大于最大编码,请检查!"));return FALSE;}m_strMinValue = strMinValue;m_strMaxValue = strMaxValue;PaddingStr(m_strMinValue);PaddingStr(m_strMaxValue);return TRUE;}BOOL CSerialNum::operator=(const CString& stringSrc){if (m_nSerialWidth < stringSrc.GetLength() ||0>=stringSrc.GetLength()){AfxMessageBox(_T("设置当前序列号时,宽度过长或过短,请检查!"));return FALSE;}if (stringSrc != stringSrc.SpanIncluding(m_strCodeCharacter)){AfxMessageBox(_T("设置的序列号中含有未识别字符,请检查!"));return FALSE;}if (1 == CompSerialNum(stringSrc, m_strMaxValue) ||1 == CompSerialNum(m_strMinValue, stringSrc)){AfxMessageBox(_T("设置序列号时,超出了范围,请检查!"));return FALSE;}m_strCrtValue = stringSrc;PaddingStr(m_strCrtValue);return TRUE;}CSerialNum::operator CString() const{return m_strCrtValue;}CString CSerialNum::GetSerialNoPadd(void){CString strRet = m_strCrtValue;if (0 >= strRet.GetLength()){AfxMessageBox(_T("严重错误,序列号为空!"));}while (strRet[0] == m_strCodeCharacter[0]){strRet.Delete(0);}return strRet;}const CString& CSerialNum::operator++(void){BOOL bCarry = FALSE;for (int n=0; n<m_strCrtValue.GetLength(); n++){m_strCrtValue.SetAt(n, GetNextCode(m_strCrtValue[n], bCarry));//没有进位,即可结束循环if (!bCarry){break;}//最高位有进位,则已经到达最大编码,复位至最小编码if (n == (m_strCrtValue.GetLength()-1)){m_strCrtValue = m_strMinValue;break;}}if (1 == CompSerialNum(m_strCrtValue, m_strMaxValue)){m_strCrtValue = m_strMinValue;}return m_strCrtValue;}const CString& CSerialNum::operator+=(int nIncrease){ASSERT(nIncrease>=0);while (nIncrease--){operator ++();}return m_strCrtValue;}

  

当然,这个类肯定还有很多可以完善的地方,还请多指教!

本文VC6.0工程源码下载地址:

http://code.google.com/p/serial-num/downloads/detail?name=SerialClass.rar&can=2&q=

最后, 非常感谢你的耐心阅读!

原创粉丝点击