John Hennesey
John Hennesey

Reputation: 375

Non-greedy negative lookbehind

In C#, I am trying to write a regular expression that will find all go statements that are the only statement on the line, and not immediately preceded by a use $(trop) statement.

I am pretty close - it is finding all go statements, but I am unable to get it right - it is finding the first one (as marked below with 'Do NOT catch this one'), but I am unable to make the negative lookbehind work properly. Can anyone help me out with what I am doing wrong?

(?<goStatement>^(\s{0,})go(\s{0,})$)(?<useTrop>(?<!(^\s{0,}use \(trop\)\s{0,}$)))`

Here's the text I'm searching:

set noexec off
:setvar trop devtip
:setvar trop_wf_tracking trop_workflow_tracking
:setvar trop_wf trop_wf

-- Information - to set this script to only run once change stop_if_applied to 1.
:setvar stop_if_applied 1


-- Do NOT catch this one
use $(trop)
go



if $(stop_if_applied) = 1 and exists (select * from $(trop).dbo.DATABASE_VERSION where DB_SCRIPT_NUMBER = 20656) begin
    select 'This db script has already been run.  If it is required to run again change the variable stop_if_applied to 0.  Disabling all further commands on the connection.'
          ,* from $(trop).dbo.DATABASE_VERSION 
    where DB_SCRIPT_NUMBER = 20656

    set noexec on
    return
end

-- DO catch this one ----------
go
-- ------------------------------------------------------------------------------

set xact_abort on

begin transaction

select * from $(trop).dbo.DATABASE_VERSION where DB_SCRIPT_NUMBER = 20656;

/* Insert your code here */

select * from dbo.SECURITY_RIGHT 
-- DO catch this one ----------
go

/* End of your code here */
-- DO catch this one ----------
go

if not exists (select * from $(trop).dbo.DATABASE_VERSION where DB_SCRIPT_NUMBER = 20656)
    insert into $(trop).dbo.DATABASE_VERSION (DB_SCRIPT_NUMBER, COMMENT)
    values (20656, 'comment goes here');

select * from $(trop).dbo.DATABASE_VERSION where DB_SCRIPT_NUMBER = 20656;

commit

Upvotes: 2

Views: 264

Answers (2)

user557597
user557597

Reputation:

Yes, the lookbehind should go before the ^go.

 (?m)                              # Multi-line mode
 (?<! use \s* \$\(trop\) \s* )     # Not a 'use $(trop)` behind 
 ^                                 # Beginning of line
 \s* go                            # The 'go'
 [^\S\r\n]*                        # Optional horizontal whitespace
 (?= \r? \n | $ )                  # until the end of line or EOS

C# test

 Regex RxGo = new Regex(@"(?m)(?<!use\s*\$\(trop\)\s*)^\s*go[^\S\r\n]*(?=\r?\n|$)");
 Match matchGo = RxGo.Match(sTarget);
 while (matchGo.Success)
 {
    Console.WriteLine("'{0}'", matchGo.Value);
    matchGo = matchGo.NextMatch();
 }

Upvotes: 1

Icemanind
Icemanind

Reputation: 48686

You should be able to use this:

(?<!(use \$\(trop\)[\r\n]))^go$

This works in your example, at least.

Upvotes: 0

Related Questions