太棒了,所以我对这类事情几乎一无所知,但这是一种有趣的工作分心,我希望能帮助你到达你需要的地方。
从 unicode 引用中可以看出,那个 emoji 字符实际上是三个混合在一起的字符。第一个是MAN,第二个是ZERO WIDTH JOINER,第三个是BOY。零宽度连接器的作用是让其他两个字符在页面中移动或选择文本时充当一个字符。您可以在任何不支持的文本编辑器(例如 SSMS)中看到这一点,您的光标将在 MAN 和 BOY 字符之间“停顿”一次方向键。
因此,为了回答您的问题,我假设您的所有 unicode 值都是三个的序列,并且中间的一个是连接器,或者,如果不是这种情况,您将能够解决问题从这里你自己。
从this very informative Stack Overflow answer 开始,您会看到SQL Server 对补充字符的处理有点不完整。因此,您需要更改数据库排序规则或帮助它,即让它知道您是否需要将 unicode 字符分解为两个 nchar 字符。因为我假设你的序列都是Emoji-Joiner-Emoji,所以这对我来说不是什么大问题,但对你来说可能是。
首先,我们需要将您的字符序列拆分为其组成部分,为此我使用了基于Jeff Moden's的计数表字符串拆分功能:
create function [dbo].[StringSplit]
(
@str nvarchar(4000) = ' ' -- String to split.
,@delimiter as nvarchar(1) = ',' -- Delimiting value to split on.
,@num as int = null -- Which value to return.
)
returns @results table(ItemNumber int, Item nvarchar(4000))
as
begin
declare @return nvarchar(4000);
-- Handle null @str values
select @str = case when len(isnull(@str,'')) = 0 then '' else @str end;
-- Start tally table with 10 rows.
with n(n) as (select n from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n(n))
-- Select the same number of rows as characters in @str as incremental row numbers.
-- Cross joins increase exponentially to a max possible 10,000 rows to cover largest @str length.
,t(t) as (select top (select len(@str) a) row_number() over (order by (select null)) from n n1,n n2,n n3,n n4)
-- Return the position of every value that follows the specified delimiter.
,s(s) as (select 1 union all select t+1 from t where substring(@str,t,1) = @delimiter)
-- Return the start and length of every value, to use in the SUBSTRING function.
-- ISNULL/NULLIF combo handles the last value where there is no delimiter at the end of the string.
,l(s,l) as (select s,isnull(nullif(charindex(@delimiter,@str,s),0)-s,4000) from s)
insert into @results
select rn as ItemNumber
,Item
from(select row_number() over(order by s) as rn
,substring(@str,s,l) as item
from l
) a
where rn = @num
or @num is null;
return;
end
使用此函数,我们可以将 unicode 序列拆分为 3 部分,并手动将数据旋转为 3 列。按照上面链接的SO答案中的解释,因为两个表情符号的CodePoint值(使用下面脚本的convert(int,(convert(varbinary(max),replace('<Your Uxxxxxxxxx unicode value>','U','0x'),1)))部分计算)在65536和1114111之间,我们需要找到 High Surrogate 和 Low Surrogate,但由于这对于零宽度连接器不是必需的,我们只需要将二进制表示传递给 nchar 函数(注意缺少转换为int):
declare @s nvarchar(50) = '\U0001F468\U0000200D\U0001F466';
select nchar(55232+(i1/1024)) + nchar(56320+(i1%1024)) -- MAN emoji
+nchar(b2) -- JOINER
+nchar(55232+(i3/1024)) + nchar(56320+(i3%1024)) -- BOY emoji
as Emoji
from(select convert(int,(convert(varbinary(max),replace(s1.Item,'U','0x'),1))) as i1
,convert(varbinary(max),replace(s2.Item,'U','0x'),1) as b2
,convert(int,(convert(varbinary(max),replace(s3.Item,'U','0x'),1))) as i3
from stringsplit(@s,'\',2) as s1
,stringsplit(@s,'\',3) as s2
,stringsplit(@s,'\',4) as s3
) as a;
通过将所有这些 nchar 值连接在一起,我们最终得到了您表情符号的正确字符表示:
输出
Emoji
-----
??