Url解码T-SQL函数不转换ascii范围字符

时间:2013-02-26 15:21:04

标签: sql-server tsql ascii urldecode non-ascii-characters

我正在使用此函数来解码url编码的字符串:

ALTER FUNCTION [dbo].[UrlDecode](@url varchar(3072)) 
RETURNS varchar(3072) 
AS 
BEGIN 
    DECLARE @Position INT,
        @Base CHAR(16),
        @High TINYINT,
        @Low TINYINT,
        @Pattern CHAR(21)

    SELECT  @Base = '0123456789abcdef',
        @Pattern = '%[%][0-9a-f][0-9a-f]%',
        @URL = REPLACE(@URL, '+', ' '),
        @Position = PATINDEX(@Pattern, @URL)

    WHILE @Position > 0
        SELECT  @High = CHARINDEX(SUBSTRING(@URL, @Position + 1, 1), @Base COLLATE Latin1_General_CI_AS),
            @Low = CHARINDEX(SUBSTRING(@URL, @Position + 2, 1), @Base COLLATE Latin1_General_CI_AS),
            @URL = STUFF(@URL, @Position, 3, CHAR(16 * @High + @Low - 17)),
            @Position = PATINDEX(@Pattern, @URL)

    RETURN  @URL + 
END 

这可以正常工作,直到它达到ascii范围字符的特殊。示例:Wil+SG+1将返回Wil SG 1,这是正常的。虽然Gen%C3%A8ve+11会返回Genève 11,但这并不是我所期望的(Genève 11是此情况下的预期结果)。

另一个例子:

select 'Gen%C3%A8ve+2+D%C3%A9p%C3%B4t', dbo.UrlDecode('Gen%C3%A8ve+2+D%C3%A9p%C3%B4t')

返回:

Gen%C3%A8ve+2+D%C3%A9p%C3%B4t   Genève 2 Dépôt

我尝试过使用NCHAR而不是CHAR,结果是一样的。你知道我能做些什么来支持这些扩展的ascii字符吗?

3 个答案:

答案 0 :(得分:3)

网址以UTF-8编码。您的函数所做的只是将URL的UTF-8表示的十六进制代码替换为与十六进制代码匹配的字符。

您真正需要的是将URL编码的UTF-8替换为MSSQL UCS-2的功能,如answer on Social.MSDN中所述。

答案 1 :(得分:2)

我发现这个功能完全符合我的要求:

ALTER FUNCTION [dbo].[UrlDecodeUTF8](@URL varchar(3072))
RETURNS varchar(3072)
AS
BEGIN 
    DECLARE @Position INT,
        @Base CHAR(16),
        @Code INT,
        @Pattern CHAR(21)

    SELECT @URL = REPLACE(@URL, '%c3', '')

    SELECT  @Base = '0123456789abcdef',
        @Pattern = '%[%][0-9a-f][0-9a-f]%',
        @Position = PATINDEX(@Pattern, @URL)

    WHILE @Position > 0
        SELECT @Code = Cast(CONVERT(varbinary(4), '0x' + SUBSTRING(@URL, @Position + 1, 2), 1) As int),
            @URL = STUFF(@URL, @Position, 3, NCHAR(@Code + 64)),
            @Position = PATINDEX(@Pattern, @URL)

    RETURN REPLACE(@URL, '+', ' ')

END

答案 2 :(得分:-1)

我怀疑你需要使用整理,用一些ascii等效替换UTF代码。这是我在代码库中的一个例子:

REPLACE(CHAR(228) COLLATE Latin1_General_BIN, CHAR(196), 'Y')