我正在为数据提取任务做准备。我需要删除一组术语;在每个源记录字符串中可能不存在、部分或全部。目标记录超过100000条。我希望避免执行单术语匹配/替换操作,因为(a)要删除的术语列表可能会增加,以及(b)每次执行一个术语的当前匹配/替换动作的时间是不可接受的。
我的问题是:如何修改正则表达式以将每个项都包含在OR分隔的列表中?
正则表达式
' and | and or | a o | company | co | c o | dba | d b a '
期望行为
将找到的每个术语(包括前缀和后缀空间)替换为一个空格。
实际行为
找到的每个"偶数"(与"奇数"相反)术语都用一个空格替换(包括前缀和后缀空间)。
示例
源字符串
' MASHABLE LTD DBA THE INFORMATION EXPERTS and and or a o company co c o dba d b a COPYRIGHT '
结果字符串(期望行为)
' MASHABLE LTD THE INFORMATION EXPERTS COPYRIGHT '
结果字符串(实际行为)
' MASHABLE LTD THE INFORMATION EXPERTS and or company c o d b a COPYRIGHT '
环境
SQL Server 2005
用户定义函数regexReplace依赖VBScript.RegExp(文章末尾提供的代码)
代码
set nocount on
declare @source [varchar](800)
declare @regexp [varchar](400)
declare @replace [char](1)
declare @globalReplace [bit]
declare @ignoreCase [bit]
declare @result [varchar](800)
set @globalReplace = 1
set @ignoreCase = 1
SET @source = ' MASHABLE LTD DBA THE INFORMATION EXPERTS and and or a o company co c o dba d b a COPYRIGHT '
set @regexp = ' and | and or | a o | company | co | c o | dba | d b a '
set @replace = ' '
select @result = master.dbo.regexReplace(@source,@regexp,@replace,@globalReplace,@ignoreCase)
print @result
产生结果:
MASHABLE LTD THE INFORMATION EXPERTS and or company c o d b a COPYRIGHT
*dbo.regex替换用户定义的函数定义*
CREATE FUNCTION [dbo].[regexReplace]
(
@source varchar(5000),
@regexp varchar(1000),
@replace varchar(1000),
@globalReplace bit = 0,
@ignoreCase bit = 0
)
RETURNS varchar(1000) AS
BEGIN
DECLARE @hr integer
DECLARE @objRegExp integer
DECLARE @result varchar(5000)
EXECUTE @hr = sp_OACreate 'VBScript.RegExp', @objRegExp OUTPUT
IF @hr <> 0
BEGIN
EXEC @hr = sp_OADestroy @objRegExp
RETURN NULL
END
EXECUTE @hr = sp_OASetProperty @objRegExp, 'Pattern', @regexp
IF @hr <> 0
BEGIN
EXEC @hr = sp_OADestroy @objRegExp
RETURN NULL
END
EXECUTE @hr = sp_OASetProperty @objRegExp, 'Global', @globalReplace
IF @hr <> 0
BEGIN
EXEC @hr = sp_OADestroy @objRegExp
RETURN NULL
END
EXECUTE @hr = sp_OASetProperty @objRegExp, 'IgnoreCase', @ignoreCase
IF @hr <> 0
BEGIN
EXEC @hr = sp_OADestroy @objRegExp
RETURN NULL
END
EXECUTE @hr = sp_OAMethod @objRegExp, 'Replace', @result OUTPUT, @source, @replace
IF @hr <> 0
BEGIN
EXEC @hr = sp_OADestroy @objRegExp
RETURN NULL
END
EXECUTE @hr = sp_OADestroy @objRegExp
IF @hr <> 0
BEGIN
RETURN NULL
END
RETURN @result
END
试试这个:
(?: (?:and or|and|a o|company|co|c o|dba|d b a))+(?!S)/i
像@mathematical.coffee一样,我一开始就分解了前导空格,并用前瞻性替换了尾随空格——在这种情况下,对于非空白字符,使用负前瞻性。这样,即使令牌是字符串中的最后一个,并且后面没有空格,它也能工作。但最重要的变化是尽可能一次更换两场或两场以上的比赛。
这不是SQL Server的问题。这是一个常见的RegEx问题,而不仅仅是通过COM访问的VBScript引擎中包含的问题。问题是新旧前缀空间之间的匹配实际上重叠。
我在中试过你的例子http://www.regextester.com/它也做同样的事情。
第一个未被替换的"and or"实际上是由第一个和"之间的空格组成的,该空格被空格替换,然后是剩余的文本。
我会考虑使用单词边界替换:Regex匹配并替换由特定字符
我推荐这个正则表达式:
( (and(?: or)?|a o|company|c ?o|d ?b ?a)(?= ))
首先,我把前缀/后缀空格放在OR括号外(效率):
( (and(?: or)?|a o|company|c ?o|d ?b ?a) )
但是,当您使用此正则表达式时,匹配项会重叠。例如,and and or
首先与and
匹配,但随后剩下的字符串是没有前面空间的and or
。
因此,为了避开这一点,我将最后一个空格改为正面展望。上面写着"确保这个模式后面有一个空格",但与空格本身不匹配。
因此,当经过and and or
时,它与and
匹配,并离开and or
,这也与模式匹配。它或多或少地消除了重叠匹配的问题。如果某个单词出现在字符串的末尾,则它将与您的某个单词不匹配,但您的原始regex无论如何都不匹配。
您可以在regexr站点上看到它的实际操作。注意,如果你用一个空格替换每个匹配项,你会得到太多的空格:
MASHABLE LTD THE INFORMATION EXPERTS COPYRIGHT
但无论如何,您的原始regex都会有这个问题。如果你完全删除匹配,你会得到:
MASHABLE LTD THE INFORMATION EXPERTS COPYRIGHT