这是一个算法,是我在做热敏打印机打印小票时解决的一个问题,想了想还是分享给大家,或许多大家有些许帮助。
在打印小票时,可能遇到一些字符串长度过长的问题,但是你不能直接截取,所以需要自动换行来显示全部名称。经过分析,其实是这么一个问题:需要把字符串分行,使得每行不得超过最大长度,最后一行长度为指定的最小长度,长度不够,用空格补齐。
先给出一个简单的效果示例图:
具体的算法源码:
#Region "把字符串按指定最大长度分行,使得最后一行长度为指定的最低长度" ''' <summary> ''' 处理字符串自动换行问题。最短为intLenMin,最长为intLenMax,最后一行用空格补齐到intLenMin长度。 ''' </summary> ''' <param name="strOldText">原字符串</param> ''' <param name="intLenMin">最短字节长度</param> ''' <param name="intLenMax">最长字节长度</param> ''' <returns>string</returns> ''' <remarks></remarks> Public Function AutomaticLine(ByVal strOldText As String, ByVal intLenMin As Integer, ByVal intLenMax As Integer) As String Dim intLength As Integer Dim strResult As String = "" '获取原字符串的字节长度 intLength = System.Text.Encoding.GetEncoding("gb2312").GetByteCount(strOldText) If intLength > intLenMax Then '总字节数> 最长截取的最长字节数, '则截取最长字节数, 然后对剩余字符串再处理 '获取字符串的UCS2码 Dim bytes As Byte() = System.Text.Encoding.Unicode.GetBytes(strOldText) '获取字符的实际截取位置 Dim intCutPos = RealCutPos(bytes, intLenMax) '采用递归调用 strResult = System.Text.Encoding.Unicode.GetString(bytes, 0, intCutPos * 2) + vbCrLf + AutomaticLine(Mid(strOldText, intCutPos + 1), intLenMin, intLenMax) ElseIf intLength > intLenMin Then '如果 最长字节数 >总字节数 > 最短字节数,则 换行,并补齐空格到最短字节数位置 strResult = strOldText + vbCrLf + Space(intLenMin) Else '如果 总字节数 < 最短字节数,则直接补齐空格到最短字节数的位置 strResult = strOldText + Space(intLenMin - intLength) End If Return strResult End Function ''' <summary> ''' 返回字符的实际截取位置 ''' </summary> ''' <param name="bytes">UCS2码</param> ''' <param name="intLength">要截取的字节长度</param> ''' <returns></returns> ''' <remarks></remarks> Public Function RealCutPos(ByVal bytes As Byte(), ByVal intLength As Integer) As Integer '获取UCS2编码 Dim intCountB As Integer = 0 ' 统计当前的字节数 Dim intCutPos As Integer = 0 '记录要截取字节的位置 While (intCutPos < bytes.GetLength(0) AndAlso intCountB < intLength) ' 偶数位置,如0、2、4等,为UCS2编码中两个字节的第一个字节 If intCutPos Mod 2 = 0 Then ' 在UCS2第一个字节时,字节数加1 intCountB += 1 Else ' 当UCS2编码的第二个字节大于0时,该UCS2字符为汉字,一个汉字算两个字节 If bytes(intCutPos) > 0 Then intCountB += 1 End If End If intCutPos += 1 End While ' 如果intCutPos为奇数时,处理成偶数 If intCutPos Mod 2 = 1 Then ' 该UCS2字符是汉字时,去掉这个截一半的汉字 If bytes(intCutPos) > 0 Then intCutPos = intCutPos - 1 Else ' 该UCS2字符是字母或数字,则保留该字符 intCutPos = intCutPos + 1 End If End If Return intCutPos / 2 End Function #End Region
由于该算法是按照字节处理的,所以可以处理中英文、数字及各种字符的混排,当截取的最后一位正好是汉字,则会自动处理到前一个字符,不会出现截取错误而导致乱码。