T-SQL中的SQL Server正则表达式解决方法?

时间:2011-08-25 20:26:53

标签: regex tsql sql-server-2008 sqlclr

我有一些SQLCLR代码用于处理Regular Expresions。但现在它已经迁移到Azure,这不允许SQLCLR,那就是了。我需要找到一种在纯T-SQL中使用正则表达式的方法。

主数据服务不可用,因为我们拥有的MSSQL版本不是R2。

所有的想法都表示赞赏,谢谢。

正则表达式匹配需要处理的样本 (在过去几年中从regexlib和其他地方剔除)

电子邮件地址

^[\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$

^(\$)?(([1-9]\d{0,2}(\,\d{3})*)|([1-9]\d*)|(0))(\.\d{2})?$

URI

^(http|https|ftp)\://([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|localhost|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$

一个数字

^\d$

百分比

^-?[0-9]{0,2}(\.[0-9]{1,2})?$|^-?(100)(\.[0]{1,2})?$

高度表示法

^\d?\d'(\d|1[01])"$

1 1000之间的数字

^([1-9]|[1-9]\d|1000)$

信用卡号码

^((4\d{3})|(5[1-5]\d{2})|(6011))-?\d{4}-?\d{4}-?\d{4}|3[4,7]\d{13}$

年份列表

^([1-9]{1}[0-9]{3}[,]?)*([1-9]{1}[0-9]{3})$
一周中的几天

^(Sun|Mon|(T(ues|hurs))|Fri)(day|\.)?$|Wed(\.|nesday)?$|Sat(\.|urday)?$|T((ue?)|(hu?r?))\.?$

12小时制的时间

(?<Time>^(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d(?:[ap]m)?)

24小时制的时间

^(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[13-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

美国电话号码

^\(?[\d]{3}\)?[\s-]?[\d]{3}[\s-]?[\d]{4}$

2 个答案:

答案 0 :(得分:4)

不幸的是,您将无法将CLR功能移动到SQL Azure。您需要使用普通的字符串函数(PATINDEX,CHARINDEX,LIKE等)或在数据库之外执行这些操作。

编辑为添加到问题中的示例添加一些信息。

电子邮件地址

这个一直存在争议,因为人们不同意他们想要支持哪个版本的RFC。例如,原文不支持撇号(或者至少人们坚持认为它没有 - 我没有从档案中挖出来并且自己阅读它,并且它必须经常扩展为新的TLD(一次用于4个字母的TLD,如.info,然后再用于6个字母的TLD,如.museum)。我经常听到知识渊博的人说完美的电子邮件验证是不可能的,而且之前曾为电子邮件服务提供商工作,我可以告诉你,这是一个不断变化的目标。但对于最简单的方法,请参阅问题TSQL Email Validation (without regex)

一个数字

可能是最简单的一群:

WHERE @s LIKE '[0-9]';

信用卡号

假设您删除了破折号和空格,无论如何都应该这样做。请注意,这不是信用卡号码算法的实际检查,以确保号码本身实际有效,只是它符合一般格式(AmEx =以3开头的15位数,其余为16位数 - Visa从4开始,MasterCard以5开头,Discover以6开头,我认为有一个以7开头(虽然可能只是某种礼品卡)):

WHERE @s + ' ' LIKE '[3-7]'+ REPLICATE('[0-9]', 14) + '[0-9 ]';

如果你想以啰嗦为代价更精确一点,你可以说:

WHERE (LEN(@s) = 15 AND @s LIKE '3'     + REPLICATE('[0-9]', 14))
   OR (LEN(@s) = 16 AND @s LIKE '[4-7]' + REPLICATE('[0-9]', 15));

美国电话号码

再次,假设您要先删除括号,破折号和空格。很确定美国地区代码不能以1开头;如果还有其他规则,我不知道。

WHERE @s LIKE '[2-9]' + REPLICATE('[0-9]', 9);

<强> -----

我不会更进一步,因为您定义的许多其他表达式可以从上面推断出来。希望这会给你一个开始。您应该能够通过Google为其他人了解其他人如何使用T-SQL复制模式。其中一些(如一周中的几天)可能只是针对一个表进行检查 - 对于一组7个可能值进行入侵模式匹配似乎有点过分。类似地,对于1000个数字或年份的列表,这些是更容易(并且可能更有效)检查数值是否在表中而不是将其转换为字符串并查看它是否与某些模式匹配的事情。 / p>

我再次声明,如果您可以在数据首先进入数据库之前清理并验证数据,那么这将会更好。你应该尽可能地努力做到这一点,因为没有CLR,你就无法在SQL Server中做强大的RegEx。

答案 1 :(得分:3)

肯·亨德森写过关于replicate RegEx without CLR的方法,但是他们需要sp_OA *程序,这些程序甚至不太可能看到Azure中的日光比CLR。您在网上找到的大多数其他文章都使用类似于Ken的方法,或者使用内置字符串函数的复杂用法。

您尝试复制RegEx的哪些部分?你能举例说明你的一个功能的输入/输出吗?也许使用像PATINDEX这样的内置字符串函数来转换以获得类似的结果很容易。