Как определить регулярное выражение с несколькими операторами ИЛИ, где каждый термин включает в себя пробел и суффикс? - PullRequest
4 голосов
/ 19 января 2012

Я готовлюсь к задаче извлечения данных.Мне нужно удалить набор терминов;нет, некоторые или все могут присутствовать в каждой строке исходной записи.Есть более 100 000 целевых записей.Я хочу избегать выполнения действий, связанных с заменой или заменой одного термина, поскольку (а) список подлежащих удалению терминов, вероятно, будет расти, и (b) время выполнения текущего действия сопоставления / замены по одному термину за разнеприемлемо.

Мой вопрос: как изменить регулярное выражение, чтобы включить каждый термин в разделенный ИЛИ список?

РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ

' 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 (код доступен в конце поста)

CODE

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

Ответы [ 3 ]

3 голосов
/ 20 января 2012

Попробуйте это:

(?: (?:and or|and|a o|company|co|c o|dba|d b a))+(?!\S)/i

Как и @ Matrix.coffee, я начал с того, что выделил начальный пробел и заменил конечный пробел с предвкушением - в данном случае отрицательный предвкушение для непробельного символа.Таким образом, он будет работать, даже если токен является последним в строке и после него не будет пробела.Но наиболее важным изменением является замена двух или более совпадений одновременно, когда это возможно.

0 голосов
/ 20 января 2012

Я бы порекомендовал это регулярное выражение:

( (and(?: or)?|a o|company|c ?o|d ?b ?a)(?= ))

Прежде всего, я ставлю пробелы префикса / суффикса вне скобок ИЛИ (эффективность):

( (and(?: or)?|a o|company|c ?o|d ?b ?a) )

Однако, когда вы используете это регулярное выражение, ваши совпадения совпадают. Например, and and or соответствует сначала and, но затем оставшаяся строка - and or, которая не имеет предшествующего пробела.

Итак, чтобы обойти это, я изменил последний пробел на позитивный взгляд. Он говорит «убедитесь, что за этим шаблоном следует пробел», но не соответствует самому пробелу.

Таким образом, при проходе через and and or он соответствует and и оставляет and or, что также соответствует шаблону. Это более или менее устраняет проблему перекрытия совпадений. Это не будет соответствовать ни одному из ваших слов, если оно встречается на конце строки, но ваше оригинальное регулярное выражение не соответствует.

Вы можете увидеть его в действии на сайте regexr . Обратите внимание, что если вы замените каждое совпадение пробелом, вы получите слишком много пробелов:

MASHABLE LTD  THE INFORMATION EXPERTS         COPYRIGHT

Но у вас все равно будет такая проблема с вашим исходным регулярным выражением. Если вы удалите спички полностью, вы получите:

MASHABLE LTD THE INFORMATION EXPERTS COPYRIGHT
0 голосов
/ 20 января 2012

Это не проблема SQL Server. Это общая проблема RegEx, а не только та, которая включена в механизм VBScript, к которому вы обращаетесь через COM. Проблема в том, что совпадения фактически перекрываются между старым и новым пробелами.

Я попробовал ваш пример в http://www.regextester.com/, и он делает то же самое.

"и или" , который является первым не замененным, на самом деле состоит из пробела из первых "и" , который был заменен пробелом, а затем из оставшихся текст.

Вместо этого я хотел бы использовать замену границы слова: Соответствие регулярному выражению и замена слова, разделенного определенными символами

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...