在未来到精确的溶液中的最大的困难是在限定恰好字符是什么要被包括(或排除,取其方向更有意义的操作)。含义:
- 我们是在谈论
VARCHAR
/ ASCII数据还是NVARCHAR
/ Unicode数据?ASCII数据的标点符号列表取决于“代码页”,而“代码页”又取决于“排序规则”。(在此问题中,我们正在处理ASCII数据)。
- 我们是在处理区分大小写还是不区分大小写的搜索?
- 列设置为什么排序规则?排序规则将告诉我们代码页和区分大小写。(在这个问题我们正在处理
Latin1_General_CI_AS
)
- 是术语“标点符号”的意思只是标准的标点字符(例如
.
,,
,;
,:
,等),或者这是否意味着非字母数字字符?
- 是否包含空格字符?
- 是否包含控制字符?
- 什么货币符号,如
¢
,£
,¥
,等?
- 那么诸如
©
和的符号™
呢?
- 什么字符被认为是“字母”?都是非英语字符如
Â
,É
,Ñ
,ß
,Þ
包括?
- 由于此问题与英国键盘有关(请参阅此问题的讨论),
Æ
/ æ
字符如何?
为了帮助简化有关预期行为的清晰度,以下查询将显示Latin1字符集的所有256个字符(即代码页1252)以及@Shaneis 提出的解决方案的两个变体如何工作。第一个字段(标记为Latin1_General_CI_AS
)显示了LIKE
@Shaneis提出的条款(截至撰写本文时),第二个字段(标记为Latin1_General_100_BIN2
)显示了一种修改形式,其中我覆盖了Collation以指定二进制数(即,以结尾的Collation _BIN2
;_BIN
排序规则已弃用,因此,如果您可以访问_BIN2
版本,请不要使用它们),这意味着我还需要添加A-Z
范围以过滤出大写字母,因为当前的排序规则不区分大小写:
;WITH nums AS
(
SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
FROM [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
CHAR(nm.[Decimal]) AS [Character],
CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM nums nm;
更新
应该提到的是,如果一个人确实在寻找被分类为“标点符号”(而不是“货币符号”,“数学符号”等)的字符,并且如果一个人不被禁止使用SQLCLR /加载自定义程序集(SQLCLR是SQL Server 2005引入的,并且我还没有遇到不允许这样做的充分理由,尤其是因为Azure SQL Database V12支持程序集SAFE
),因此可以使用正则表达式,但是不能因为大多数人的缘故会猜到。
\w
您可以指定要过滤的字符的Unicode类别,而不是使用正则表达式来构建功能更强的字符范围,甚至不使用类似的东西(表示任何“单词”字符),而无需使用诸如此类的东西。:
https://www.regular-expressions.info/unicode.html#category
您甚至可以指定要过滤的Unicode块,例如“ InBengali”或“ InDingbats”或“ InOptical_Character_Recognition”等:
https://www.regular-expressions.info/unicode.html#block
有许多为SQL Server创建RegEx函数的示例(尽管大多数示例未遵循SQLCLR最佳实践),或者您可以下载SQL#库的免费版本(由我创建),并按如下方式使用标量RegEx_IsMatch函数:
SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)
该\p{P}
表达式表示\p
= Unicode类别,并且{P}
=所有标点符号(与特定类型的标点符号相反,例如“连接器标点符号”)。并且,“标点符号”类别包括所有语言的所有标点符号!您可以通过以下链接在Unicode.org网站上查看完整列表(该类别中当前有717个代码点):
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D
测试查询的更新版本如上图所示,包括使用另一场SQL#.RegEx_IsMatch用\p{P}
,和跨代码页1252(即Latin1_General)的所有256个字符的所有3次测试的结果已在被张贴在PasteBin.com:
T-SQL查询和用于过滤字符类型的结果
更新
在相关讨论中提到了以下内容:
您已经对重音符号提出了很好的要求,因为它们是来自世界各地的酒店名称,所以名称中会包含重音符号,对于我的问题,我想将它们归类为有效的字母字符。
在这种情况下:
Latin1字符集/代码页中包含11个非英语字符,它们与a-z
范围不匹配。它们是:ð Ð Þ þ œ Œ š Š ž Ž Ÿ
。这些需要添加到通配符中,虽然目前没有必要,但是添加起来不会有什么坏处,A-Z
这样该模式在区分大小写的排序规则中也可以很好地工作。最终结果是:
LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'
考虑到该数据可以包含“来自世界各地的酒店名称”,因此我强烈建议将列的数据类型更改为,NVARCHAR
以便可以存储所有语言的所有字符。保持这种状态VARCHAR
存在极高的最终数据丢失风险,因为您只能代表基于拉丁语的语言,而对于那些提供了其他与拉丁语有关的字符的六个补充Unicode类别的语言,它们甚至还不能完全代表。