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

问题描述 投票:14回答:2

当qzxswpoi与字符串函数结合使用时,它在T-SQL中有一些奇怪的行为。这里发生了什么?我错过了什么吗?其他角色是否遇到同样的问题?

Hawaiian quote

另外,例如在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
sql-server tsql unicode collation
2个回答
8
投票

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

一些东西:

  1. 这不是夏威夷语“引用”:它是影响发音的“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. ”。
  2. 这不是“怪异”的行为:它不是你所期待的。
  3. 这种行为并不是一个“问题”,尽管是的,还有其他字符表现出类似的行为。例如,以下字符(U + 02DA Ring Above)的行为略有不同,具体取决于它所在字符的哪一侧: glottal stop

现在,任何使用SQL Server 2008或更高版本的人都应使用100(或更新)级别的排序规则。他们在100系列中添加了许多排序权重和大写/小写映射,这些映射不在90系列中,或者是非编号系列,或者是大多数过时的SQL Server排序规则(名称以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_):

U+0312 Combining Turned Comma Above

问题是这是一个“间距修饰符”字符,因此它根据您正在处理的修饰符来附加并修改字符之前或之后的含义/发音。

根据;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 ̒ */ ,第7.8节(修饰字母),第323页(文件,而不是PDF):

7.8编辑信件

在Unicode标准中使用的意义上的修饰符字母是通常与其他字母相邻写入并以某种方式修改其用法的字母或符号。它们没有正式组合标记(gc = Mn或gc = Mc),也没有以图形方式与它们修改的基本字母组合。它们本身就是基本字符。他们修改其他字母的意义更多的是它们在使用中的语义问题;它们通常倾向于起作用,就好像它们是变音符号,表示字母发音的变化,或以其他方式区分字母的用法。通常,这种变音符号修改适用于修饰符字母前面的字符,但修饰符字母有时可能会修改后续字符。有时,修饰符字母可以简单地代表它自己的声音。 ...

Spacing Modifier Letters: U+02B0–U+02FF

语音用法。此块中的大多数修饰符都是语音修饰符,包括覆盖国际音标所需的字符。在许多情况下,修饰符用于表示相邻字母的发音在某种程度上是不同的 - 因此称为“修饰符”。它们也用于标记压力或音调,或者可以简单地表示它们自己的声音。

以下示例应该有助于说明。我正在使用100级排序规则,它需要是重音敏感的(即名称包含Unicode Standard, Chapter 7 (Europe-I)):

_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(假设您使用的是SQL Server 2005或更高版本)。含义:

  • SQL Server 2000:BIN
  • SQL Server 2005:Latin1_General_BIN
  • SQL Server 2008,2008 R2,2012,2014和2016:Latin1_General_BIN2
  • SQL Server 2017及更新版本:Latin1_General_100_BIN2

如果您对我推荐的原因感到好奇,请参阅:

Japanese_XJIS_140_BIN2

有关排序/ Unicode /编码/等的更多信息,请访问:Differences Between the Various Binary Collations (Cultures, Versions, and BIN vs BIN2)


2
投票

我无法提供详细的答案,但我可以提供满足您期望的解决方案。

这与排序规则有关,但我不确定为什么Windows排序规则会产生意外结果。如果您使用二进制排序规则,您将获得预期的结果(请参阅Solomons关于使用哪个BIN的优秀答案):

Collations Info

返回SELECT REPLACE(N'aʻ' COLLATE Latin1_General_BIN, N'a', N'_')

返回:

DECLARE @table TABLE ([Name] NVARCHAR(MAX))
INSERT INTO
    @table
VALUES
    (N'John'),
    (N'Jane'),
    (N'Hawaiʻi'),
    (N'Hawai''i'),
    (NCHAR(699))

SELECT
    *
FROM
    @table
WHERE
    [Name] like N'%ʻ%' COLLATE Latin1_General_BIN

您可以使用以下代码检查哪个校对确认您的期望(改编自@SolomonRutzky(Hawaiʻi ʻ )的代码)。它评估所有排序规则的source

SELECT REPLACE(N'"ʻ', N'ʻ', N'_')) = '"_'
© www.soinside.com 2019 - 2024. All rights reserved.