2

我正在使用这个函数来解码 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 字符吗?

4

3 回答 3

3

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

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

于 2013-02-26T20:19:09.883 回答
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
于 2013-02-27T07:37:47.387 回答
-1

我怀疑您需要使用排序规则,用一些等效的 ascii 替换 UTF 代码。这是我的代码库中的一个示例:

REPLACE(CHAR(228) COLLATE Latin1_General_BIN, CHAR(196), 'Y')
于 2013-02-26T17:47:40.487 回答