我有一系列像这样的unicode:
\ U0001F468 \ U0000200D \ U0001F466
如何在T-SQL中将其转换为相应的表情符号并将表情符号插入nvchar类型列?
答案 0 :(得分:3)
Hooooookay所以我对这类事情几乎一无所知,但这是一种有趣的工作分心,我希望能帮助你达到你需要的目标。
从您的unicode引用中可以看到,表情符号字符实际上是三个字符,它们全部混合在一起。第一个是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 ,但由于Zero Width Joiner不需要这样做,我们只需要将二进制表示传递给{{1函数(注意缺少转换为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