特殊字符(夏威夷语“Okina”)导致奇怪的字符串行为

2024-03-11

The 夏威夷语报价 https://en.wikipedia.org/wiki/%CA%BBOkina当 T-SQL 与字符串函数结合使用时,它会出现一些奇怪的行为。这里发生了什么?我错过了什么吗?其他角色是否也遇到同样的问题?

SELECT UNICODE(N'ʻ') -- Returns 699 as expected.

SELECT REPLACE(N'"ʻ', '"', '_') -- Returns "ʻ, I expected _ʻ

SELECT REPLACE(N'aʻ', 'a', '_') -- Returns aʻ, I expected _ʻ

SELECT REPLACE(N'"ʻ', N'ʻ', '_') -- Returns __, I expected "_

SELECT REPLACE(N'-', N'ʻ', '_') -- Returns -, I expected -

另外,在使用时很奇怪LIKE例如:

DECLARE @table TABLE ([Name] NVARCHAR(MAX))
INSERT INTO
    @table
VALUES
    ('John'),
    ('Jane')

SELECT
    *
FROM
    @table
WHERE
    [Name] LIKE N'%ʻ%' -- This returns both records. I expected none.

当夏威夷语引号与字符串函数结合使用时,T-SQL 中的夏威夷语引号有一些奇怪的行为。 ...其他角色是否也遇到同样的问题?

一些东西:

  1. 这不是夏威夷语“引言”:这是“声门塞音 https://en.wikipedia.org/wiki/Hawaiian_phonology#Glottal_stop”这会影响发音。
  2. 这不是“奇怪”的行为:这只是不是您所期望的。
  3. 这种行为并不是一个具体的“问题”,尽管是的,还有其他角色表现出类似的行为。例如,以下字符(U+02DA 上方环形)的行为略有不同,具体取决于它位于字符的哪一侧:

    SELECT REPLACE(N'a˚aa' COLLATE Latin1_General_100_CI_AS, N'˚a',  N'_'); -- Returns a_a
    SELECT REPLACE(N'a˚aa' COLLATE Latin1_General_100_CI_AS, N'a˚',  N'_'); -- Returns _aa
    

现在,任何使用 SQL Server 2008 或更高版本的人都应该使用 100(或更高版本)级别的排序规则。他们在 100 系列中添加了许多 90 系列中没有的排序权重和大写/小写映射,或非编号系列,或大多数过时的 SQL Server 排序规则(名称以SQL_).

这里的问题不在于它不等于任何其他字符(二进制排序规则之外),事实上它实际上等于另一个字符(U+0312 组合上面的转逗号 https://unicode-table.com/en/0312/):

;WITH nums AS
(
  SELECT TOP (65536) (ROW_NUMBER() OVER (ORDER BY @@MICROSOFTVERSION) - 1) AS [num]
  FROM   [master].sys.all_columns ac1
  CROSS JOIN   [master].sys.all_columns ac2
)
SELECT nums.[num] AS [INTvalue],
       CONVERT(BINARY(2), nums.[num]) AS [BINvalue],
       NCHAR(nums.[num]) AS [Character]
FROM   nums
WHERE  NCHAR(nums.[num]) = NCHAR(0x02BB) COLLATE Latin1_General_100_CI_AS;
/*
INTvalue    BINvalue    Character
699         0x02BB      ʻ
786         0x0312      ̒
*/

问题是,这是一个“间距修饰符”字符,因此它附加到其之前或之后的字符,并修改其含义/发音,具体取决于您正在处理的修饰符字符。

根据Unicode 标准,第 7 章(欧洲-I) https://www.unicode.org/versions/Unicode12.0.0/ch07.pdf,第 7.8 节(修饰符字母),第 323 页(文档的,而不是 PDF 的):

7.8 修饰字母

修饰符字母,就 Unicode 标准中使用的意义而言,是通常与其他字母相邻书写并以某种方式修改其用法的字母或符号。它们没有正式组合标记(gc = Mn 或 gc = Mc),也没有以图形方式与它们修改的基本字母组合。他们本身就是基本人物。它们修饰其他字母的意义更多的是它们在使用中的语义问题。它们往往起到变音符号的作用,表示字母发音的变化,或以其他方式区分字母的用途。通常,此变音符号修饰适用于修饰符字母之前的字符,但修饰符字母有时可能会修饰后面的字符。有时,修饰字母可能只是单独代表其自己的声音。
...

间距修饰符字母:U+02B0–U+02FF

语音用法。该块中的大多数修饰符字母都是语音修饰符,包括覆盖国际音标所需的字符。在许多情况下,修饰符字母用于指示相邻字母的发音在某些方面有所不同,因此得名“修饰符”。它们还用于标记重音或音调,或者可能只是代表它们自己的声音。

 
下面的例子应该有助于说明。我使用的是 100 级排序规则,并且它需要区分重音(即名称包含_AS):

SELECT REPLACE(N'ʻ'    COLLATE Latin1_General_100_CI_AS, N'ʻ',   N'_'); -- Returns _
SELECT REPLACE(N'ʻa'   COLLATE Latin1_General_100_CI_AS, N'ʻ',   N'_'); -- Returns _a
SELECT REPLACE(N'ʻaa'  COLLATE Latin1_General_100_CI_AS, N'ʻ',   N'_'); -- Returns _aa
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻ',   N'_'); -- Returns __aa

SELECT REPLACE(N'ʻaa'  COLLATE Latin1_General_100_CI_AS, N'ʻa',  N'_'); -- Returns ʻ__
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'ʻa',  N'_'); -- Returns aʻ__

SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'aʻ',  N'_'); -- Returns _aa
SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'aʻa', N'_'); -- Returns _a

SELECT REPLACE(N'aʻaa' COLLATE Latin1_General_100_CI_AS, N'a',   N'_'); -- Returns aʻ__
SELECT REPLACE(N'אʻaa' COLLATE Latin1_General_100_CI_AS, N'א',   N'_'); -- Returns אʻaa
SELECT REPLACE(N'ffʻaa' COLLATE Latin1_General_100_CI_AS, N'ff',   N'_'); -- Returns ffʻaa
SELECT REPLACE(N'ffaa'  COLLATE Latin1_General_100_CI_AS, N'ff',   N'_'); -- Returns _aa



SELECT CHARINDEX(N'a', N'aʻa' COLLATE Latin1_General_100_CI_AS); -- 3
SELECT CHARINDEX(N'a', N'aʻa' COLLATE Latin1_General_100_CI_AI); -- 1



SELECT 1 WHERE N'a' = N'aʻ' COLLATE Latin1_General_100_CI_AS; -- (0 rows returned)
SELECT 2 WHERE N'a' = N'aʻ' COLLATE Latin1_General_100_CI_AI; -- 2

如果您需要以忽略其预期语言行为的方式处理这些字符,那么是的,您必须使用二进制排序规则。在这种情况下,请使用最新级别的排序规则,并且BIN2代替BIN(假设您使用的是 SQL Server 2005 或更高版本)。意义:

  • SQL Server 2000:Latin1_General_BIN
  • SQL Server 2005:Latin1_General_BIN2
  • SQL Server 2008、2008 R2、2012、2014 和 2016:Latin1_General_100_BIN2
  • SQL Server 2017 及更高版本:Japanese_XJIS_140_BIN2

如果您好奇我为什么提出该建议,请参阅:

各种二进制排序规则之间的差异(文化、版本以及 BIN 与 BIN2) https://sqlquantumleap.com/2019/03/13/differences-between-the-various-binary-collations-cultures-versions-and-bin-vs-bin2/

并且,有关排序规则/Unicode/编码/等的更多信息,请访问:校对信息 https://collations.info/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

特殊字符(夏威夷语“Okina”)导致奇怪的字符串行为 的相关文章

随机推荐