Регулярные выражения отрицательного просмотра вперед

Я делаю гимнастику регулярного выражения. Я поставил перед собой задачу попытаться найти код C#, где есть использование as-оператора, за которым не следует нулевая проверка в разумном объеме пространства. Сейчас я не хочу анализировать код на C#. Например. Я хочу захватить фрагменты кода, такие как

    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(x1.a == y1.a)
, не
    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(x1 == null)

не

    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(somethingunrelated == null) {...}
    if(x1.a == y1.a)

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

вопрос: как мне сопоставить что-то, гарантируя, что что-то еще не найдено в его sourroundings.

Я пробовал наивный подход, ища "как", а затем делал отрицательный lookahead в пределах 150 символов.

basb.{1,150}(?!b==s*nullb)

приведенное выше регулярное выражение соответствует всем приведенным выше примерам, к сожалению. Моя интуиция говорит мне, проблема в том, что глядя вперед, а затем делать отрицательный взгляд может найти много ситуаций, когда lookahead не находит '== null'.

если я попытаюсь отрицать все выражение, то это тоже не поможет, при этом будет соответствовать большинству кода C#.

6 ответов


Я любовь regex гимнастика! Вот комментарий PHP regex:

$re = '/# Find all AS, (but not preceding a XX == null).
    \bas\b               # Match "as"
    (?=                  # But only if...
      (?:                # there exist from 1-150
        [\S\s]           # chars, each of which
        (?!==\s*null)    # are NOT preceding "=NULL"
      ){1,150}?          # (and do this lazily)
      (?:                # We are done when either
        (?=              # we have reached
          ==\s*(?!null)  # a non NULL conditional
        )                #
      | $                # or the end of string.
      )
    )/ix'

и вот он в стиле Javascript:

re = /\bas\b(?=(?:[\S\s](?!==\s*null)){1,150}?(?:(?===\s*(?!null))|$))/ig;

от этого у меня немного болела голова...

вот тестовые данные, которые я использую:

text = r"""    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(x1.a == y1.a)

however, not capture
    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(x1 == null)

nor for that matter
    var x1 = x as SimpleRes;
    var y1 = y as SimpleRes;
    if(somethingunrelated == null) {...}
    if(x1.a == y1.a)"""

поставить .{1,150} внутри lookahead и замените . С \s\S (вообще, . не соответствует новым строкам). Кроме того,\b может вводить в заблуждение возле ==.

\bas\b(?![\s\S]{1,150}==\s*null\b)

Я думаю, что это поможет поместить имя переменной в (), чтобы вы могли использовать его в качестве обратной ссылки. Что-то вроде следующего,

\b(\w+)\b\W*=\W*\w*\W*\bas\b[\s\S]{1,150}(?!\b\b\W*==\W*\bnull\b)

вопрос не понятен. Чего именно ты хочешь ? Я сожалею, но я все еще не понимаю, прочитав вопрос и комментарии много раз.

.

должен ли код быть на C# ? В Python ? Другие ? Нет никаких указаний относительно этого пункта

.

вы хотите соответствие только если if(... == ...) строка следует за блоком var ... = ... линии ?

или может быть гетерогенная линия между блоком и if(... == ...) линия без остановки сопоставления ?

мой код принимает второй вариант как true.

.

тут if(... == null) строка после if(... == ...) остановка в комплекте или нет ?

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

.

Я надеюсь, что мой код будет достаточно ясным и ответит на вашу озабоченность.

это в Питон

import re

ch1 ='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
1618987987849891
'''

ch2 ='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)
3213546878'''

ch3='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1 == null)
165478964654456454'''

ch4='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
hgyrtdduihudgug
if(x1 == null)
165489746+54646544'''

ch5='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(somethingunrelated == null ) {...}
if(x1.a == y1.a)
1354687897'''

ch6='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
ifughobviudyhogiuvyhoiuhoiv
if(somethingunrelated == null ) {...}
if(x1.a == y1.a)
2468748874897498749874897'''

ch7 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
iufxresguygo
liygcygfuihoiuguyg
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''

ch8 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
iufxresguygo
liygcygfuihoiuguyg
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''

ch9 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''

pat1 = re.compile(('('
                   '(^var +\S+ *= *\S+ +as .+[\r\n]+)+?'
                   '([\s\S](?!==\s*null\b))*?'
                   '^if *\( *[^\s=]+ *==(?!\s*null).+$'
                   ')'
                   ),
                  re.MULTILINE)

pat2 = re.compile(('('
                   '(^var +\S+ *= *\S+ +as .+[\r\n]+)+?'
                   '([\s\S](?!==\s*null\b))*?'
                   '^if *\( *[^\s=]+ *==(?!\s*null).+$'
                   ')'
                   '(?![\s\S]{0,150}==)'
                   ),
                  re.MULTILINE)


for ch in (ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9):
    print pat1.search(ch).group() if pat1.search(ch) else pat1.search(ch)
    print
    print pat2.search(ch).group() if pat2.search(ch) else pat2.search(ch)
    print '-----------------------------------------'

результат

>>> 
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)

var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)

var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)
-----------------------------------------
None

None
-----------------------------------------
None

None
-----------------------------------------
None

None
-----------------------------------------
None

None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)

None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)

None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)

None
-----------------------------------------
>>> 

позвольте мне попытаться переопределить вашу проблему:

  1. ищите назначение" как " -- вам, вероятно, нужно лучшее регулярное выражение для поиска фактических назначений и может потребоваться сохранить назначенное выражение, но давайте использовать "\bas\b" сейчас
  2. если вы видите if (... == null) в 150 символов, не соответствуют
  3. если вы не видите if (... == null) в пределах 150 символов, матч

выражение \bas\b.{1,150}(?!\b==\s*null\b) не будет работать из-за негативного взгляда вперед. Регулярное выражение всегда может пропустить вперед или позади одной буквы, чтобы избежать этого негативного взгляда вперед, и вы в конечном итоге совпадаете, даже если есть if (... == null) там.

Regex действительно не хороши в не что-то сопоставления. В этом случае вам лучше попытаться сопоставить назначение "as" с проверкой "if == null" в пределах 150 символов:

\bas\b.{1,150}\b==\s*null\b

и затем отрицание чека:if (!regex.match(text)) ...


(?s:\s+as\s+(?!.{0,150}==\s*null\b))

я активирую опцию SingleLine с помощью ?s:. Вы можете поместить его в параметры вашего регулярного выражения, если хотите. Добавлю, что ставлю \s вокруг as потому что я думаю, что только пробелы "правового" вокруг as. Вы, вероятно, можете поставить \b как

(?s:\b+as\b(?!.{0,150}==\s*null\b))

имейте в виду, что \s вероятно, поймает пробелы, которые не являются "допустимыми пробелами". Это определяется как [\f\n\r\t\v\x85\p{Z}] здесь \p{Z} is символы Юникода в 'Пробел' Категория плюс символы Юникода в категории "разделитель, строка" плюс символы Юникода в категории "разделитель, абзац".