【问题标题】:How to remove weird Excel character in SQL Server?如何删除 SQL Server 中奇怪的 Excel 字符?
【发布时间】:2018-03-28 14:01:37
【问题描述】:

从 Excel 导入时,我的数据中偶尔会出现一个奇怪的空白字符,我似乎无法摆脱它。显然,它是一个空白字符,但 SQL Server 将其视为问号(ASCII 63)。

declare @temp nvarchar(255); set @temp = 'carolg@c?am.com'
select @temp

返回:

?carolg@c?am.com

如何在不去掉真正问号的情况下去掉空格?如果我查看每个“?”的ASCII码我得到了 63 个字符,而事实上,其中只有一个是真正的问号。

【问题讨论】:

  • 如果您执行 Ltrim(@temp) 会怎样?
  • 注意:如果由于某种原因,您想保持字符串不变,您可以使用set @temp = N'mystring'(明确声明字符串是 unicode,即使您的变量是 @987654324,您也应该这样做@) 而不是你目前正在做的事情。
  • 看起来像是字符集不匹配。
  • 您的问题似乎不包含您正在讨论的角色。请添加它。 @ZLK 为您的演示代码提供了答案,但我认为在 Excel 中您没有使用该代码。那么,你真正的代码是什么?
  • @TomBlodget ...当我复制/粘贴时,它没有出现。字符原来是“0x0B20”(零宽度空间的unicode)。下面的答案解决了它。

标签: sql-server excel special-characters data-cleaning


【解决方案1】:

查看this answer 寻找有类似问题的人。对不起,如果这有点啰嗦:

SQL Server 似乎通过将无法表示的字符(没有合适的替换)映射到问号来将 Unicode 扁平化为 ASCII。要复制这一点,请尝试打开 Character Map Windows 程序(应该安装在大多数机器上),选择 Arial 作为字体并找到 U+034f “Combining Grapheme Joiner”。选择此字符,复制到剪贴板并将其粘贴在下面的单引号之间:

declare @t nvarchar(10)
set @t = '͏'
select rtrim(ltrim(@t)) -- we can try and trim it, but by this stage it's already a '?'

你会得到一个问号,因为它在将这个非 ASCII 字符转换为varchar 时不知道如何表示它。如前所述,要强制它接受它作为双字节字符 (nvarchar),您需要改用 N''。在上面的引号之前添加一个N,问号就会消失(但原始的不可见字符会保留在输出中 - 并且ltrim 和rtrim 不会将其删除,如下所示):

declare @t nvarchar(10), 
        @s varchar(10) -- note: single-byte string
set @t = rtrim(ltrim(N'͏')) -- trimming doesn't work here either
set @s = @t 
select @s -- still outputs a question mark

导入的数据肯定可以做到这一点,我以前见过,像我上面展示的那样的字符特别难以诊断,因为你看不到它们!你需要创建某种清理过程以删除这些不可打印的内容(以及任何其他垃圾字符,就此而言),并确保您在任何地方都使用nvarchar,否则您最终会遇到这个问题。更糟糕的是,那些虚幻的问号会变成真正的问号,你将无法与合法的问号区分开来。

要查看您正在处理的字符代码,您可以转换为 varbinary,如下所示:

declare @t nvarchar(10)
set @t = N'͏test?'
select cast(@t as varbinary) -- returns 0x4F0374006500730074003F00

-- Returns:
-- 0x4F03  7400 6500 7300 7400 3F00
-- badchar  t    e    s    t    ?

现在摆脱它:

declare @t nvarchar(10)
set @t = N'͏test?'
select cast(@t as varbinary) -- bad char
set @t = replace(@t COLLATE Latin1_General_100_BIN2, nchar(0x034f), N'');
select cast(@t as varbinary)  -- gone!

注意我必须将字节顺序从0x4f03 交换到0x034f(同样的原因“t”出现在输出中作为0x7400,而不是0x0074)。有关我们为什么使用二进制排序规则的一些说明,请参阅this answer。

这有点混乱,因为你不知道脏字符是什么,它们可能是成千上万种可能性中的一种。一种选择是使用like 甚至unicode() function 遍历字符串,并丢弃不在可接受字符列表中的字符串中的字符,但这可能会很慢。可能您的大多数坏字符都位于字符串的开头或结尾,如果您认为可以做出这样的假设,这可能会加快此过程。

如果要导入大量数据,您可能需要构建 SQL Server 外部或作为 SSIS 导入的一部分的附加流程,以根据我在上面向您展示的内容快速去除这些流程。如果您不确定执行此操作的最佳方法,最好在新问题中回答。

希望对你有帮助。

【讨论】:

  • 很好的解释!简直要疯了。在我的情况下,字符是“0x0B20”...... unicode 用于零宽度空间。 WTF 这意味着,我不知道。
猜你喜欢
  • 2015-10-19
  • 2015-09-16
  • 1970-01-01
  • 2014-10-04
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多