使用特殊字符检查字符串是否有效

Checking if a string is valid with special chars

我正在使用 PATINDEX 来验证列是否包含无效的特殊字符。但是我遇到了一些字符问题。

SELECT PATINDEX(N'%[^a-zA-Z0-9 !"&''()*+,-./:;?=%~@[]_{}\|<>]%' collate SQL_Latin1_General_CP850_BIN, 'abc╢123' collate SQL_Latin1_General_CP850_BIN)

有效字符为 ! " & ' ( ) * + , - . / : ; ? = % ~ @ [ ] _ { } \ | < >

不是有效字符之一,但 PATINDEX 仍然是 returns 0。

还有其他验证方法吗?

问题似乎是由模式中的 ] 引起的。您可以将 LIKE 运算符与 ESCAPE 一起使用。最小示例:

-- valid characters are digits, "[" and "]"
SELECT val
     , expected
     , CASE WHEN val LIKE '%[^0-9[]]%'             THEN 'Bad' ELSE 'Good' END AS wrong_pattern
     , CASE WHEN val LIKE '%[^0-9[\]]%' ESCAPE '\' THEN 'Bad' ELSE 'Good' END AS right_pattern
FROM (VALUES
    ('12345', 'Good'),
    ('[123]', 'Good'),
    ('ABCDE', 'Bad'),
    ('123', 'Bad')
) AS t(val, expected)

所以你的模式可以写成:

SELECT CASE WHEN 'abc╢123!"&''()*+,-./:;?=%~@[]_{}\|<>' NOT LIKE '%[^a-z0-9 [\]\!"&''()*+,\-./:;?=%~@_{}|<>]%' ESCAPE '\' THEN 'Good' ELSE 'Bad' END

我逃脱了 ]-\。字符 %_ 在方括号内不作为通配符,因此不会转义。

转义是一种方法。
但是,如果您只想忽略可读的 ASCII 字符,则可以简化范围。

[^ -~] :不在 space 和 ~

之间
-- Sample data
declare @T table (col NVARCHAR(30) collate SQL_Latin1_General_CP850_BIN primary key);
insert into @T (col) values
(N'abc╢123'),
(N'xyz123[}'''),
(N'abc௹123');

-- Query
SELECT col, PATINDEX(N'%[^ -~]%' collate  SQL_Latin1_General_CP850_BIN, col) as pos
FROM @T;

Returns:

col         pos
--------    ----
abc╢123     4
abc௹123     4
xyz123[}'   0

但要同时定位插入符号和其他一些,则比较复杂。
因为 PATINDEX 不像 LIKE 那样有 ESCAPE。

-- Sample data
declare @T table (
 id int identity(1,1) primary key, 
 col NVARCHAR(30) collate SQL_Latin1_General_CP850_BIN
 );
insert into @T (col) values
 (N'xyz[123]}''') -- good
 ,(N'abc╢123') -- bad
,(N'abc௹123') -- bad
,(N'def#456') -- bad
,(N'def^456') -- bad
;

-- also locate #, ´ , ` and ^
SELECT col, 
CASE 
WHEN PATINDEX(N'%[^ !"$-_a-z{-~]%' collate  SQL_Latin1_General_CP850_BIN, col) > 0
THEN PATINDEX(N'%[^ !"$-_a-z{-~]%' collate  SQL_Latin1_General_CP850_BIN, col) 
ELSE CHARINDEX(N'^' collate  SQL_Latin1_General_CP850_BIN, col)
END AS pos
FROM @T;

Returns:

xyz[123]}'  0
abc╢123     4
abc௹123     4
def#456     4
def^456     4