Unicode到非unicode转换

时间:2014-11-21 12:49:34

标签: sql sql-server unicode character-encoding

我在名为PostalCode的NVarchar字段中有一些unicode字符。当我将它们转换为Varchar时,结果中有?

我的代码是:

select PostalCode, cast((PostalCode) as varchar)) as val from  table

结果是:

PostalCode       |   val
053000           | 053000?

我在这里得到一个'?'在结果中。有没有办法删除这些特殊字符?

4 个答案:

答案 0 :(得分:4)

这里有几点需要注意:

  1. 如果你想确切地看到那个字符,你可以将值转换为VARBINARY,它将为你提供字符串中所有字符的十六进制/二进制值,并且没有“隐藏的“十六进制字符:

    DECLARE @PostalCode NVARCHAR(20);
    SET @PostalCode = N'053000'+ NCHAR(0x2008); -- 0x2008 = "Punctuation Space"
    SELECT @PostalCode AS [NVarCharValue],
           CONVERT(VARCHAR(20), @PostalCode) AS [VarCharValue],
           CONVERT(VARCHAR(20), RTRIM(@PostalCode)) AS [RTrimmedVarCharValue],
           CONVERT(VARBINARY(20), @PostalCode) AS [VarBinaryValue];
    

    返回:

    NVarCharValue   VarCharValue   RTrimmedVarCharValue   VarBinaryValue
    053000          053000?        053000?                0x3000350033003000300030000820
    

    NVARCHAR数据存储为UTF-16,工作在2字节集合中。查看最后4个十六进制数字以查看隐藏的2字节集是什么,我们看到“0820”。由于Windows和SQL Server是UTF-16 Little Endian(即UTF-16LE),因此字节的顺序相反。翻转最后2个字节 - 0820 - 我们得到“2008”,这是我们通过NCHAR(0x2008)添加的“标点符号空间”。

    此外,请注意RTRIM在这里没有任何帮助。

  2. 简单地说,你可以用任何东西替换问号:

    SELECT REPLACE(CONVERT(VARCHAR(20), [PostalCode]), '?', '');
    
  3. 更重要的是,您应该将[PostalCode]字段转换为VARCHAR,以便它不会存储这些字符。没有国家使用未在ASCII字符集中表示且对VARCHAR数据类型无效的字母,至少就我读过的内容而言(参见底部参考)。实际上,允许的是ASCII的一个相当小的子集,这意味着您可以轻松地在路上进行过滤(或者在插入或更新时只执行与上面所示相同的REPLACE):

    ALTER TABLE [table] ALTER COLUMN [PostalCode] VARCHAR(20) [NOT]? NULL;
    

    请务必检查列的当前NULL / NOT NULL设置,并在上面的ALTER语句中将其设置为相同,否则可以将其更改为默认值NULL未指定。

  4. 如果您无法更改表的架构并需要定期“清理”错误数据,则可以运行以下命令:

    ;WITH cte AS
    (
       SELECT *
       FROM   TableName
       WHERE  [PostalCode] <>
                      CONVERT(NVARCHAR(50), CONVERT(VARCHAR(50), [PostalCode]))
    )
    UPDATE cte
    SET    cte.[PostalCode] = REPLACE(CONVERT(VARCHAR(50), [PostalCode]), '?', '');
    

    请注意,如果表包含数百万行,则上述查询无效。此时,需要通过循环在较小的集合中处理。


  5. 供参考,以下是Postal code的维基百科文章,该文章目前声明所使用的唯一字符是:

      
        
    • 阿拉伯数字“0”至“9”
    •   
    • ISO基本拉丁字母的字母
    •   
    • 空格,连字符
    •   

    关于字段的最大大小,这里是维基百科List of postal codes

答案 1 :(得分:0)

不,Unicode是Unicode。该标准允许ASCII之外的无数“特殊”字符。您可以做的最好的事情是在转换之前搜索所需的字符子集,并将它们转换为您喜欢的ASCII替身。

答案 2 :(得分:0)

只要“?”在实际的PostalCode值中不允许,您可以先进行强制转换,然后使用REPLACE删除这些字符,将其替换为空字符串:

replace(cast((PostalCode) as varchar))), '?', '')

警告

这些'?'个字符表示原始nvarchar值中未转换为等效ASCII varchar字符的Unicode字符。这意味着此方法将以静默方式删除任何此类字符。你说你想删除这些字符,但你可能想重新考虑一下。

举个例子,如果邮政编码可以包含字母,并且有人不小心输入了带重音的字母:

  

1234-ABCD

最终结果将是:

  

1234-BCD

答案 3 :(得分:0)

如果您只想移除最后一个特殊字符,其余部分保持不变,您可以尝试以下其中一项将删除,然后转换为{{ 1}}:

RTRIM

也许最后一个特殊角色被认为是一个空间。试试RTRIM

varchar

识别并删除

首先,使用RIGHTUNICODE从表格的示例行中找到该最后一个字符的Unicode代码点:

cast(rtrim(PostalCode) as varchar))

这应该给你一个整数。

接下来,在不需要时从行中删除该字符。我们可以使用NCHAR将该整数转换回unicode字符:

select unicode(right(PostalCode, 1)) from …