[B]十六进制字符串转换为整型

公司的产品是使用Delphi编写的,其中用户的密码是用Delphi编写的一个加密函数加密后存储到数据库的。
因为系统要和门户网站做集成,门户网站要使用系统中的用户登陆,所以也就需要对存储在数据库中的密码进行解密。
门户网站是使用ASP.NET开发的,负责这部分开发的同事需要一个可以解密的存储过程,也就是说将Delphi编写的解密函数改写成SQL Server的存储过程。

Delphi编写的这个解密函数并不复杂,所以我就开始着手写。但是写的时候发现解密函数需要将十六进制的字符串转换成整型进行操作。
在Delphi中这很容易实现,只要在字串前加上$,然后StrToInt就行了,如下:

Result := StrToInt('$' + S);
可是我在SQL Server中找了半天也没找到可以完成十六进制字符串转十进制整型的方法。 
 
在SQL Server中可以完成十六进制到整型的转换(0xFF-> int),但却无法完成十六进制字符串到整型的转换('0xFF' -> int)。
以下的转换是正确的:
select cast(0xFF as int)
输出:255
但是以下的转换不正确:
select cast(cast('0xFF' as varbinaryas int)
输出:813188678
可见 varchar -> varbinary -> int 这样的转换路径是行不通的。
然而下面的转换又是正确的:
select cast(cast(cast(0xFF as varcharas varbinaryas int)

输出:255
可见'0xFF'和cast(0xFF as varchar)得到的字符串是不一样的。
varchar值是可以显式转换成varbinary的,只不过0xFF这个varbinary值对应的varchar值并不是'0xFF'这个字符串。
那么cast(0xFF as varchar)得到的到底是什么呢?
其实cast(0xFF as varchar)得到的就是0xFF(255)对应的ASCII字符。
所以我们只要找到0xFF对应的这个ASCII字符,然后通过ascii函数就可以得到它的值了。也就是通过 '0xFF' -> ASCII字符 -> int 这样的转换路径。

select ascii('')

输出:255
上面单引号中间的部分就是0xFF对应的ASCII字符,看起来象两个空格,实际上却是一个字符(你可以选中它看看)。
但是获取这个ASCII字符,我们就要通过cast(0xFF as varchar)这样的操作,然而我们仍然无法完成'0xFF' -> 0xFF这样的转换。

在网上搜了半天也没找到答案,只在Microsoft的Help and Support站点上找到了一个二进制转十六进制字符串的方法。
文中说到SQL Server没有内置的T-SQL函数实现该转换,所以写了一个存储过程来实现这种转换。
于是我得到启发,既然SQL Server没有提供十六进制字符串转十进制整型的方法,不如自己来写一个,反正也不是很复杂。
下面就是实现十六进制字符串转整型的存储过程:

 1create procedure hex_to_int(@hex varchar(10))
 2as
 3declare
 4  @start int,
 5  @index int,
 6  @count int,
 7  @rez bigint
 8
 9set @start = 3
10set @index = 1
11set @count = len(@hex- 2
12set @rez = 0
13
14while @index <= @count begin
15  set @rez = @rez + 
16  (case substring(@hex@start + @index - 11
17    when 'A' then 10
18    when 'B' then 11
19    when 'C' then 12
20    when 'D' then 13
21    when 'E' then 14
22    when 'F' then 15
23    else cast(substring(@hex@start + @index - 11as bigint
24  end* power(16, (@count - @index))
25
26  set @index = @index + 1
27end
28
29select 'hex_to_int' = @rez
30go

P.S 该存储过程未对输入的字符进行有效性的判断,所以当输入非法字符的时候会引发转换错误,在对字串进行处理前应该先扫描字串,要求字串必须前两位为'0x',以及从第三位起不能出现0-9,A-F以外的字符等等,有兴趣的朋友可以加上。如果你完善了该存储过程别忘了发一份给我。:)