'转载http://cyinger-smiling.blogbus.com/logs/5672032.html
Private Function QpDecode(inString As String) As String
Dim myB As Byte
Dim myByte1 As Byte, myByte2 As Byte
Dim convStr() As Byte
Dim mOutByte As Byte
Dim FinishPercent As Long
Dim TotalB, k As Long
Dim tmpByte As Byte
convStr = StrConv(inString, vbFromUnicode)
TotalB = UBound(convStr)
For k = 0 To TotalB
myB = convStr(k)
If myB = Asc("=") Then
k = k + 1
myByte1 = convStr(k)
If myByte1 = &HA Then
'如果是回车,继续
Else
'取第二个字节
k = k + 1
myByte2 = convStr(k)
Call DecodeByte(myByte1, myByte2, mOutByte)
If mOutByte >= 127 Then
If tmpByte <> 0 Then
QpDecode = QpDecode & Chr(Val("&H" & Hex(tmpByte) & Hex(mOutByte)))
tmpByte = 0
Else
tmpByte = mOutByte
End If
Else
QpDecode = QpDecode & Chr(mOutByte)
tmpByte = 0
End If
End If
Else
mOutByte = myB
QpDecode = QpDecode & Chr(mOutByte)
End If
Next
End Function
Private Sub DecodeByte(mInByte1 As Byte, mInByte2 As Byte, mOutByte As Byte)
Dim tbyte1 As Integer, tbyte2 As Integer
If mInByte1 > Asc("9") Then
tbyte1 = mInByte1 - Asc("A") + 10
Else
tbyte1 = mInByte1 - Asc("0")
End If
If mInByte2 > Asc("9") Then
tbyte2 = mInByte2 - Asc("A") + 10
Else
tbyte2 = mInByte2 - Asc("0")
End If
mOutByte = tbyte1 * 16 + tbyte2
End Sub
Private Sub EncodeByte(mInByte As Byte, mOutStr As String)
If (mInByte >= 33 And mInByte <= 60) Or (mInByte >= 62 And mInByte <= 126) Then
mOutStr = Chr(mInByte)
Else
If mInByte <= &HF Then
mOutStr = "=0" & Hex(mInByte)
Else
mOutStr = "=" & Hex(mInByte)
End If
End If
End Sub
QP编码的规则是,对于信息中的7位字符不作重新编码,而是仅将8位的数据转成7位即可。我们可以看到,QP编码是字符对应的编码,每个未编码的二进制字符都会被编码成3个字符,即一个等号加上两个该字符的16进制值,如“=A8”,但这样的编码数为1:3,所以编码效率相对于其它编码方式而言相当低。但不可否认的是,这种编码方法非常简单,特别适合那些数据大多数是7位的ASCII码文本、偶尔插入8位字符的情况,但遗憾的是对汉字编码效果不够好,因为每个双字节汉字经过编码后会变成6个字节。具体规则如下:
①将一个字元用两个十六进制数表示,然后前面再加上一个「=」(等号)字元;除非这个字元符合下面其他的规则。比如原先 ASCII 的「=」(等号)字元,其十进制数值是 61,十六进制数值为 3D,所以经过 QP 编码后,变成了「=3D」。
②字元的数值(十进制数)介于 33 到 60、及 62 到 126 者不必经过编码。(61 是「等号」)
③字元 TAB 或 SPACE 可以不经编码,但是不经编码的 TAB 或SPACE 不可以放在编码后每行字串的末尾;也就是說编码后的內容,一行字串中如果有 TAB 或 SPACE 的話,其后面一定还有其它的字元。
QP解码只是编码的逆过程,计算出每个等号后的两个十六进制字符所代表的数值进行解码,对于码值小于128的,单字节表示一个字符;大于128的,双字节表示一个字符。下面举例分析。例如:编码后的字符串为=C4=E3=BA=C3,解码后对应字符串为“你好”。表3.3.3-2: QP解码示例
|
十六进制值 |
= |
C |
4 |
= |
E |
3 |
= |
B |
A |
= |
C |
3 |
| 解码(十进制值) |
196 |
227 |
186 |
195 |
| 解码(二进制值) |
11000100 11100011 |
10111010 11000011 |
| 原字符 |
你 |
好 |
以上两个函数分析如下:
DecodeByte()函数是私有函数,对QP编码后的每组(以等号分割的每两个字节一组)信息进行QP解码,即计算这两个十六进制字符所代表的数值。当ASCII码小于“9”的ASCII码时,则减去“0”的ASCII码值(这是因为,当字符小于9时为了使编码位数一致,除在其前加“=”外还加了“0”);如果大于则减去“A”的ASCII码值再加10,即得到此位对应的十进制值,如“B”对应十进制值11。然后通过高字节*16+低字节得到解码数值。
QpDecode()函数是私有函数,先用StrConv函数将QP编码后的字符串信息由Unicode转成系统的缺省码,然后将其分组(以等号分割,每两个字节一组)后调用DecodeByte()函数进行QP解码。第一个等号前及最后一个等号后三位起的字符不作QP解码(直接是ASCII编码)。对于DecodeByte()返回值小于128的(单字节字符)单字节表示一个字符,大于128(双字节字符)的两个字节表示一个字符。
上面的解码是有问题的,对于一个扩展ASCII码,其值是大于127的,但它不是双字节,依然是一个字节,上面的解码函数不够全面!