纯 T-SQL 中的 URL 解码






4.33/5 (2投票s)
2007年1月25日
4分钟阅读

82272

180
如何在 T-SQL 中解码 URLEncoded URL。
引言
这是一篇关于如何在 T-SQL 中执行 URL 解码的短文。这是我最近需要做的事情,我努力在公共领域找到一个合适的解决方案,所以我决定自己编写一个。它完成的方式有些不寻常,因为表示编码字符的十六进制数并没有被视为数字,而是在整个过程中被视为字符串。我将首先完整地列出代码,因为它不是很长,然后我将逐步讲解,边讲边解释。
代码
CREATE FUNCTION fnURLDecode
(
@input nvarchar(4000)
)
RETURNS nvarchar(4000)
AS
BEGIN
declare @char nvarchar(2)
declare @asc nvarchar(2)
declare @asc2 nvarchar(2)
while (charindex('%', @input) > 0)
begin
set @char=(select substring(@input, charindex('%',
@input) +1, 2))
if (isnumeric(substring(@char, 1, 1)))>0
begin
set @asc=(select cast(substring(@char, 1, 1)
as int))*16
end
else
begin
set @asc=(select ascii(cast(substring(@char, 1, 1)
as char)))-55
set @asc=(select @asc*16)
end
if (isnumeric(substring(@char, 2, 1)))>0
set @asc=(select cast(@asc as int) +
(select cast(substring(@char, 2, 1) as int)))
else
begin
set @asc2=(select ascii(cast(substring(@char, 2, 1)
as char)))-55
set @asc=(select cast(@asc as int) +
(select cast(@asc2 as int)))
end
set @input=
(select substring(@input, 0, charindex('%', @input)))
+ char(@asc) + (select substring(@input, charindex('%',
@input)+3, len(@input)))
end
return @input
END
正如你所看到的,这并不是有史以来最长的代码,但某些部分非常复杂,需要一些解释。我可以简化一些行,但超过一定程度后,您最终会为了简化而创建变量。我认为它大部分都足够清晰易懂了。
解释
让我们从头开始。我们从函数声明开始。这是一个 SQL Server 用户定义函数,它将一个字符串作为参数。它也返回一个字符串,一旦它被完全解码。然后我们定义三个变量。可能可以用更少的变量完成,但最后我用了三个。这些变量将存储 2 个字符组合。在第一种情况下,这些将是字符代码的十六进制部分,例如 "%20" 中的 "20"(空格)。在整个过程中,这些将被转换为它们所代表的字符。
从这里,我们进入一个 while 循环。循环条件基于 charindex 函数,具体来说,我们正在寻找下一个 "%" 字符的实例。在 URL 字符串中,此字符标识我们正在寻找的十六进制字符代码。该函数在进行过程中会调整输入字符串,因此首先处理第一个代码,更新字符串,当循环再次启动时,我们正在寻找第二个代码。最终,字符串中将不再有 "%" 的实例,循环将退出(当 charindex 函数的结果为 0 时)。
现在我们将 @char 设置为紧随当前 "%" 实例之后的 2 个字符。这是我们想要的密码。我们分别处理代码的每个字符。一个两位数的十六进制数可以通过将第一位数字乘以 16(只要它是数字的开头)并将第二位数字加到它来转换为十进制数(同样,只要它是数字)。这就是我们接下来要做的。首先,第一位数字是数字吗?如果是,我们应用上述公式,如果不是,我们做一些转换。
这部分更有趣。我没有尝试说服 SQL Server "A" 也可以是一个数字,而不仅仅是一个字符,我作弊了。 "A" 的 ASCII 码是 65。十六进制中的 "A" 代表数字 10。因此,十六进制数字 A-F 的十进制值只是它们的 ASCII 码减去 55。因此,如果我们当前查看的数字不是数字,我们应用此规则以获取其实际值。
举例来说,假设我们已经得到了以下字符代码:"%3F",这是"?"的代码。我们的例程寻找 "%",它就在开头。我们得到接下来的两个字符 "3F"。我们查看第一个字符,它是数字,所以我们将其乘以 16。到目前为止,这留下了 48,还需要添加 "F"。 "F" 不是数字,所以我们应用其他规则。F 的 ASCII 码是 70。我们从中减去 55 得到 15(F 的正确值)。我们将 15 加到我们的 48 中,得到 63。我们使用 chr 函数将此数字转换为其 ASCII 等价物,我们得到 "?",正如我们想要的。
该函数处理输入字符串,对每个编码字符应用上述推理。当它到达字符串的末尾时,它退出循环并返回解码后的字符串。
结论
我不相信这是将十六进制代码转换为 ASCII 字符的最佳方法,但它确实有效,并且在没有更好的方法的情况下,我将其提供出来供使用。由于该例程的工作方式,也可以从中剥离位,并将其用作通用十六进制->十进制转换器。反转该过程也应该允许您对字符进行编码,尽管需要编写一些代码来规定哪些字符需要转换。
此代码是在缺乏睡眠和一些莫名其妙的横向思维的产物。我希望它对某人有帮助。