虽然
接受的答案有效,并且在涉及“宽”字符的主要问题上是正确的,但问题中存在一些误解和技术细节,应该予以解决,以便更好地理解在.NET和SQL Server中实际发生了什么。
首先:
我有两个字符串,一个带有双字节值,另一个是单字节。
不,你并没有。你有两个Unicode字符串,编码为UTF-16小端(这是Windows和.NET的工作方式)。虽然在实际情况下,大多数情况下字符是双字节的,但这仅涵盖了62,000-63,000个字符(即U+0000和U+FFFF之间的代码点或0-65,535个“有效”字符)。但Unicode允许映射超过1.1百万个代码点,并且目前已经映射了260,000个以上的代码点
(已经映射)。 U+FFFF / 65,535以上的代码点称为补充字符,映射到两个双字节值集合,称为代理对。因此,虽然它们使用较少,但大多数Unicode代码点实际上是4个字节。
第二:
字符串比较结果返回false,如何使它们正确比较?
中的字母被称为"全角"字符。您可以在此处查看它们的完整列表:
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:East_Asian_Width=Fullwidth:]
一些关于为什么会存在不同宽度的解释可以在这里找到:
http://unicode-table.com/en/blocks/halfwidth-and-fullwidth-forms/
如果您想比较问题中的两个字符串是否相等,您可以使用String.Compare(String, String, CultureInfo, CompareOptions)方法(如@ Arnout的答案中所述),或者您可以按照以下方式使用CompareInfo.Compare(String, String, CompareOptions):
CompareInfo.Compare(s1, s2, CompareOptions.IgnoreWidth)
第三点:
在同样的情况下,如果你有一个 SQL Server 中的 nvarchar 列,其中包含值为 smatsumoto11 的数据,在使用条件为 smatsumoto11 的 where 子句查询数据时将返回同一行。
这是一种潜在的危险思维方式,用于比较字符串。在几乎所有数据库中,字符串没有特定的比较方式,除非字符串在7位ASCII(值为0-127)中,这甚至不包括代码页,而且我不知道这是否是一个选项。比较基于特定的LCID / Locale / Culture / Collation。SQL Server中的默认排序规则(至少在美国)是
SQL_Latin1_General_CP1_CI_AS
,它是大小写不敏感和重音符号敏感的。它还使用Code Page 1252(影响CHAR / VARCHAR数据,而不是NCHAR / NVARCHAR),以及“en-US”文化。其他文化/ LCID的排序规则可能不等同于全角和“半角”。而且,排序规则名称中有
_WS
的排序规则肯定不会等同于这两个字符串,因为
_WS
代表“宽度敏感”,如果您不指定
CompareOptions.IgnoreWidth
选项,则是.NET比较的默认设置。
如果你运行以下的查询来查找名称中有 _WS
的排序规则,你会发现在 SQL Server 2012 中,共有 3885 个排序规则中有 1776 个是区分宽度的,它们不会匹配这两个字符串。当然,还有262个二进制排序规则(即以废弃的 _BIN
或优先的 _BIN2
结尾的名称),它们也不会使这两个字符串相等,但这并不是宽度敏感的问题。
SELECT *
FROM sys.fn_helpcollations()
WHERE [name] LIKE N'%[_]WS%'
ORDER BY [name];
此外,正如我刚提到的,不幸的是(已经被弃用的)默认排序规则
SQL_Latin1_General_CP1_CI_AS
,甚至更好的版本
Latin1_General_100_CI_AS
是不区分大小写的。因此,您要比较的字符串都是小写字母,因此在仅使用
CompareOptions.IgnoreWidth
时它们是相等的,但如果您想在 SQL Server 中模拟这些特定的排序规则,则 .NET 的默认行为是区分大小写的将无法匹配 SQL Server 行为。为了更好地匹配 SQL Server 行为(至少对于那些排序规则或任何标记为具有
_CI
而没有
_WS
的排序规则),您还需要包括
CompareOptions.IgnoreCase
选项,如下所示:
CompareInfo.Compare(s1, s2, CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase)
String.Compare(s1, s2, CultureInfo.CurrentCulture,
CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase)
额外资源:
.NET Framework 中比较字符串
.NET Framework 中使用字符串的最佳实践
string
对象中,则它已经处于2字节形式。可能这些字符串来自不同的代码页或编码,因此与您的预期不同。 - Binary Worrier